{"record":{"id":"5d7bf572596fb70b","repo":"paperclipai/paperclip","slug":"could-not-clean-managed-github-launchers","errorCode":null,"errorMessage":"Could not clean managed GitHub launchers","messagePattern":"Could not clean managed GitHub launchers","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/adapter-utils/src/execution-target.ts","lineNumber":1543,"sourceCode":"};\n\nfunction githubOperationLauncherDirectory(input: GitHubLauncherLocation): string {\n  // Only controller-generated run IDs may name a removable directory.\n  if (!/^[a-zA-Z0-9_-]+$/.test(input.runId)) throw new Error(\"Invalid GitHub launcher run ID\");\n  return input.target?.kind === \"remote\"\n    ? path.posix.join(input.target.remoteCwd, \".paperclip-runtime\", \"github\", input.runId)\n    : path.join(os.tmpdir(), \"paperclip-github-runtime\", input.runId);\n}\n\n/** Call only after execution settles, before releasing its remote environment lease. */\nexport async function cleanupGitHubOperationLaunchers(input: GitHubLauncherLocation): Promise<void> {\n  const directory = githubOperationLauncherDirectory(input);\n  if (input.target?.kind === \"remote\") {\n    const result = await adapterExecutionTargetCommandRunner(input.target).execute({\n      command: \"sh\", args: [\"-c\", `rm -rf -- ${shellQuote(directory)}`],\n      cwd: input.target.remoteCwd, timeoutMs: 5_000,\n    });\n    if (result.exitCode !== 0) throw new Error(\"Could not clean managed GitHub launchers\");\n  } else {\n    await fs.rm(directory, { recursive: true, force: true });\n  }\n}\n\nasync function githubOperationLauncherBasePath(\n  target: AdapterCommandCapableExecutionTarget | null,\n  env: Record<string, string>,\n): Promise<string> {\n  if (!target) return env.PATH || process.env.PATH || \"/usr/bin:/bin\";\n  const configuredPath = sanitizeRemoteExecutionEnv(env).PATH;\n  if (configuredPath !== undefined) return configuredPath;\n\n  // The provider owns login/profile setup. Query its effective PATH before\n  // staging BASH_ENV, rather than substituting the controller's toolchain or\n  // a minimal PATH that hides legacy NVM/user-local agent installations.\n  const result = await adapterExecutionTargetCommandRunner(target).execute({\n    command: \"sh\",","sourceCodeStart":1525,"sourceCodeEnd":1561,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/adapter-utils/src/execution-target.ts#L1525-L1561","documentation":"After execution settles, the managed GitHub launcher directory is removed: on remote targets via `sh -c 'rm -rf -- <dir>'` executed through the target's command runner, locally via fs.rm. A non-zero exit code from the remote rm raises this error, meaning stale launcher files may remain on the remote host.","triggerScenarios":"Remote rm -rf fails due to insufficient permissions on the directory, a read-only or full remote filesystem, the directory being locked by a still-running process, or SSH/connection problems yielding a non-zero exit.","commonSituations":"Remote CI host with a full disk; launcher directory owned by a different user after a permission change; remote lease released while processes still hold files; flaky SSH connection during cleanup.","solutions":["SSH into the remote target and manually run `rm -rf <remoteCwd>/.paperclip-runtime/github/<runId>` to clear the stale directory","Check remote disk space and permissions on .paperclip-runtime","Retry the cleanup after the remote environment is healthy and no processes hold the files"],"exampleFix":"// manual remediation on remote host\nssh user@remote 'rm -rf ~/repo/.paperclip-runtime/github/<runId>'","handlingStrategy":"retry","validationCode":"const probe = await runner.execute({ command: 'sh', args: ['-c', 'test -d <dir> && test -w <dir>'], timeoutMs: 5000 });\nif (probe.exitCode !== 0) console.warn('launcher dir missing or not writable; cleanup will no-op/fail');","typeGuard":null,"tryCatchPattern":"try {\n  await cleanManagedLaunchers(input);\n} catch (e) {\n  if (String(e.message).includes('Could not clean managed GitHub launchers')) {\n    console.warn('remote cleanup failed; remove the directory manually later');\n  } else throw e;\n}","preventionTips":["Ensure the remote user owns .paperclip-runtime before runs","Monitor remote disk space; full disks break rm -rf","Release leases only after all child processes on the target have exited"],"tags":["cleanup","remote-execution","filesystem"],"backgroundTag":"file-write-failed","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}