{"record":{"id":"5f81bf4c0f61070b","repo":"paperclipai/paperclip","slug":"daytona-post-upload-command-failed-exit-result","errorCode":null,"errorMessage":"Daytona post-upload command failed (exit ${result.exitCode ?? \"unknown\"})${detail ? `: ${detail}` : \"\"}","messagePattern":"Daytona post-upload command failed \\(exit (.+?)\\)(.+?)` : \"\"\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/daytona/src/file-sync.ts","lineNumber":789,"sourceCode":"      if (plan.compressed) {\n        // `zstd -d -o` copies the mode of its INPUT (the uploaded `.zst`\n        // scratch) onto its output with its own `chmod` call. That call runs\n        // AFTER creation, so it overrides any `umask` in effect — a mapping\n        // with no explicit `mode` must not rely on the scratch file's mode\n        // being owner-only already. Always `chmod` the decompressed file\n        // right after decompression: to the mapping's `mode` when set, or to\n        // owner-only (0600) otherwise. The pre-refactor decompression step\n        // applied the same 0600 default. The raw (uncompressed) path above\n        // applies no `chmod` when the mapping sets no `mode`, so the two\n        // inbound branches do not use the same no-mode default today.\n        const targetMode = typeof plan.mapping.mode === \"number\" ? plan.mapping.mode : 0o600;\n        renameScript.push(\n          `zstd -d -o ${shellQuote(plan.rawScratch)} ${shellQuote(plan.compressed.zstdScratch)} || { echo \"decompress failed\"; exit 49; };`,\n          `chmod ${toOctalModeString(targetMode)} ${shellQuote(plan.rawScratch)} || { echo \"chmod failed\"; exit 50; };`,\n        );\n      }\n      renameScript.push(\n        `mv -f ${shellQuote(plan.rawScratch)} ${shellQuote(plan.mapping.targetPath)} || { echo \"rename failed\"; exit 43; };`,\n      );\n      if (plan.compressed) {\n        // Clean up the `.zst` scratch after a successful promotion. `|| true`\n        // keeps a cleanup failure from becoming the promote script's own exit\n        // status — every target file is already in place by this point, so a\n        // stray `.zst` scratch must never read back as a sync failure.\n        renameScript.push(`rm -f ${shellQuote(plan.compressed.zstdScratch)} || true;`);\n      }\n    }\n    // `promote` span: move the staged temp onto its target. When this batch\n    // decompressed at least one mapping, this span also carries\n    // `transfer.decompress.wall_ms`. That value measures the WHOLE promote\n    // command — every decompression and every `mv` — not decompression alone.\n    // Treat it as an upper bound on the decompress wall time, not an exact\n    // measurement.\n    await withProviderSpan({\n      name: \"promote\",\n      wallMsAttr: hasCompressedMapping ? SPAN_ATTR.transferDecompressWallMs : undefined,","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/daytona/src/file-sync.ts#L771-L807","documentation":"Post-upload failure check in syncInFileMappings: a caller-supplied postUploadCommand run verbatim in the sandbox (after the cwd symlink-escape guard) exited non-zero or timed out, so the remaining queued commands are aborted per the C4 fail-fast rule. The detail includes the command's captured output.","triggerScenarios":"Thrown at packages/plugins/sandbox-providers/daytona/src/file-sync.ts:767 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Inspect the exit code and detail; fix the post-upload command and retry."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}