paperclipai/paperclip · error · Error
sandbox runtime asset key collides with a reserved runtime…
Error message
sandbox runtime asset key collides with a reserved runtime archive name: ${key} What it means
Thrown by assertRuntimeAssetKeyIsSafe when a runtime asset key is exactly "workspace" or "git-workspace". Those stems are reserved: the asset archive would share its path with the workspace archive, and under concurrent sync the two tasks would write/upload the same file simultaneously, corrupting extraction or leaking asset bytes into the workspace, so the runtime fails closed.
Solutions
- Rename the key to any unreserved single-segment value, e.g. "workspace-assets" or "ws-overlay".
- Treat the reserved set {"workspace", "git-workspace"} as off-limits when generating keys programmatically (mirror RESERVED_RUNTIME_ASSET_KEYS).
- If you meant to sync the workspace itself, use the workspace sync path, not a runtime asset.
Example fix
// before
const assets = [{ key: "workspace", source: archivePath }];
// after
const assets = [{ key: "workspace-overlay", source: archivePath }]; Defensive patterns
Strategy: validation
Validate before calling
const RESERVED = new Set(["workspace", "git-workspace"]);
function isUsableRuntimeAssetKey(key: string): boolean {
return isSafeRuntimeAssetKey(key) && !RESERVED.has(key);
} Type guard
function isUnreservedAssetKey(key: string): boolean {
return key !== "workspace" && key !== "git-workspace";
} Try / catch
try {
buildRuntimeAssets(assets);
} catch (error) {
if (error instanceof Error && error.message.includes("reserved runtime archive name")) {
assets = assets.map((a) => a.key === badKey ? { ...a, key: `${a.key}-assets` } : a);
} else throw error;
} Prevention
- Treat {"workspace", "git-workspace"} as a blocklist when generating keys.
- Do not name assets after top-level runtime directories.
- Add a manifest lint step that flags reserved keys before submission.
When it happens
Trigger: A SandboxRemoteExecutionSpec runtimeAssets entry uses key "workspace" or "git-workspace" (e.g. author intended to ship a prebuilt workspace); assertRuntimeAssetKeyIsSafe rejects it before sync at sandbox-managed-runtime.ts:774.
Common situations: Reusing a natural directory name as the asset key; converting an older manifest that happened to name its asset "workspace"; tooling that defaults keys to the top-level folder name being archived.
Related errors
- sandbox runtime asset key is not a simple path segment
- A sandbox command is required.
- Bridge host response body capacity is busy.
- CreateOS lease cleanup is already in progress.
- CreateOS lease cleanup must finish before resume.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-08-21).
Data as JSON: /api/errors/af6ebd8f52e678f0.
Report an issue: GitHub.
Appendix: source
Thrown at packages/adapter-utils/src/sandbox-managed-runtime.ts:445
}
/**
* A control command run against the sandbox after a sync operation's files have
* landed. Mirrors the plugin SDK `PluginPostUploadCommand`; kept as a local
* structural type so `adapter-utils` does not depend on the plugin SDK. Ordered
* within {@link SandboxSyncOperation.postUploadCommands} and executed in array
* order, fail-fast (first non-zero exit or timeout aborts the operation).
*
* SECURITY — command origin (Stage-1 design review, condition C1). `command` is
* a **Paperclip/adapter-authored control operation**: it may be supplied ONLY by
* core/adapter code. No server route, issue/comment content, project/workspace
* file content, provider-plugin callback, or arbitrary adapter config may supply
* a raw `command` string; any path embedded in it MUST be built by adapter/core
* helpers from already-confined paths and shell-quoted (C3). Providers treat the
* command as **opaque** — execute or reject, never rewrite/concatenate/append.
*/
export interface SandboxPostUploadCommand {
/** The opaque, adapter-authored shell command to run after upload. */
command: string;
/**
* Working directory for the command. When present, MUST be an absolute POSIX
* path confined under the operation's allowed sandbox target root (C2). When
* absent, defaults to the runtime's stable command cwd — never a process
* default cwd.
*/
cwd?: string;
/** Optional per-command timeout in milliseconds. */
timeoutMs?: number;
}
/**
* An ordered, opaque unit of work handed to the native sync transport. The
* `operationId` is an opaque, non-sensitive token authored by the orchestrator
* (never a caller/asset identifier that could leak intent); a provider MUST NOT
* interpret it.
*/View on GitHub (pinned to 3f1d897a7c)