Skip to content

fix(pi): restore a snapshot of an empty workspace - #311

Merged
earakely-scale merged 1 commit into
scaleapi:mainfrom
salma2vec:fix/285-pi-empty-workspace-snapshot
Oct 22, 2026
Merged

earakely-scale merged 1 commit into
scaleapi:mainfrom
salma2vec:fix/285-pi-empty-workspace-snapshot

Conversation

@salma2vec

@salma2vec salma2vec commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

What and why

Closes #285

PiAgent.load_snapshot restores the workspace with _unpack, which extracts the archive into a staging directory and then iterates it. The archive of an empty workspace has no members, so tarfile.extractall never creates the staging directory, and staging.iterdir() raised FileNotFoundError. PUT /ext/snapshot therefore failed with HTTP 500 and the conversation was not installed for the target context. The A2A validator's snapshot step hits this, since it snapshots an agent that hasn't written to its workspace.

It's slightly worse than "nothing happens": _unpack removes the workspace's current contents before it iterates the staging directory. So a non-empty workspace restored from an empty snapshot ends up emptied anyway, while the request reports a failure.

The fix creates the staging directory before extracting (staging.mkdir() at the top of the try), so an empty archive restores as an empty workspace. That's the approach the issue suggests and the one the OpenHands agent (#281) uses. A failed extraction still leaves the workspace untouched (test_a_workspace_archive_that_fails_to_extract_changes_nothing), and the finally still removes the staging directory.

How it was tested

  • New test_an_empty_workspace_archive_restores_an_empty_workspace: _pack an empty directory, _unpack it over a workspace holding one file, and expect an empty workspace. It fails on main with the FileNotFoundError from the issue and passes here.
  • A by-hand check of the same case on main: FileNotFoundError is raised and the workspace's file is already gone. With this change the restore completes and leaves an empty workspace.
  • pytest tst/unit/agents/pi: 41 passed (40 on main plus the new test).
  • ruff check clean on both files.

Found and fixed with Claude Code. The runs above were executed locally.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

This PR appears safe to merge.

Summary

Creates the staging directory before extracting a Pi workspace snapshot, so an empty archive restores successfully.

  • Empty workspace snapshots restore as empty workspaces.

Reviews (1) · Last reviewed commit: "fix(pi): restore a snapshot of an empty ..." · Reviewed by Greptile

_unpack extracted the workspace archive into a staging directory and then
iterated it, but an empty workspace's archive has no members, so
extractall never created the directory and iterdir raised
FileNotFoundError: loading the snapshot failed with HTTP 500 after the
existing workspace contents had already been removed. Create the staging
directory before extracting, as the OpenHands agent does.

Closes scaleapi#285

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@salma2vec
salma2vec requested a review from a team as a code owner October 22, 2026 21:22
@earakely-scale

Copy link
Copy Markdown
Collaborator

Thanks for making these fixes!

@earakely-scale
earakely-scale merged commit b84c5c5 into scaleapi:main Oct 22, 2026
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pi: loading a snapshot of an empty workspace fails with FileNotFoundError

2 participants