Repository navigation
Snapshot archive is not closed when sandbox workspace setup fails #3595
Description
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 invokedA 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