Skip to content

Snapshot archive is not closed when sandbox workspace setup fails #3595

Open

Description

@pengmoubuaixuexi

Describe the bug

AbstractBaseSandbox.start() opens a snapshot archive before setting up the workspace, but enters the try-with-resources block only after doSetupWorkspace() returns. If setup throws, the already-opened archive is never closed. Both the lost-workspace recovery branch (B) and initial snapshot restoration branch (C) are affected.

The ordering was introduced in #3562. This is a separate archive-stream ownership issue, not the duplicate remote-sandbox issue addressed there. For file-backed or remote-download snapshots, the unclosed stream can retain the underlying resources when startup fails.

To Reproduce

On current main, add a test in io.agentscope.harness.agent.sandbox that exercises the public start() method:

InputStream archive = mock(InputStream.class);
SandboxSnapshot snapshot = mock(SandboxSnapshot.class);
when(snapshot.isRestorable()).thenReturn(true);
when(snapshot.restore()).thenReturn(archive);
SandboxState state = new SandboxState() {};
state.setWorkspaceSpec(new WorkspaceSpec());
state.setWorkspaceRootReady(false); // also reproduces with true and probe returning false
state.setSnapshot(snapshot);
AbstractBaseSandbox sandbox = mock(AbstractBaseSandbox.class,
        withSettings().useConstructor(state).defaultAnswer(CALLS_REAL_METHODS));
doReturn(false).when(sandbox).probeWorkspaceRootForPreservedResume();
doThrow(new IOException("workspace setup failed")).when(sandbox).doSetupWorkspace();
assertThrows(SandboxException.WorkspaceStartException.class, sandbox::start);
verify(archive).close(); // fails: close() was never invoked

A local parameterized regression covers both branches, including a stream whose close() also throws. Run:

mvn -B -T1 -pl agentscope-harness -am -Dtest=AbstractBaseSandboxSnapshotCleanupTest -Dsurefire.failIfNoSpecifiedTests=false test

Result before the fix: 4 tests run, 4 failures, 0 errors; all fail because InputStream.close() is not invoked.

Expected behavior

Once an archive has been opened, it is closed on both successful restoration and workspace setup failure. A setup exception remains the primary cause if closing also fails, with the close exception suppressed.

Error logs

Wanted but not invoked: inputStream.close();
Actually, there were zero interactions with this mock.

Environment

  • AgentScope Java: main c416c378e0b4c1f4849bf75d66084c00bff62cef (2.1.0-SNAPSHOT)
  • Java: 17.0.20.1
  • OS: Windows
  • No external sandbox service or credentials required for the reproduction.

Additional context

SandboxSnapshot.restore() documents caller ownership of the returned stream. Moving workspace setup inside the existing try-with-resources block in both branches preserves setup-before-hydration ordering while closing the archive on failure.

I am implementing the fix and regression tests and will submit a linked PR. Please assign this issue to me if assignment is used for tracking. Investigation and tests are assisted by Codex; results above were run locally.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions