{"record":{"id":"a2442f7ed9656f3c","repo":"paperclipai/paperclip","slug":"device-login-failed-the-sandbox-login-command-err","errorCode":null,"errorMessage":"device login failed: the sandbox login command errored.","messagePattern":"device login failed: the sandbox login command errored\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/adapters/codex-local/src/server/device-login-runner.ts","lineNumber":196,"sourceCode":"      return { outcome: \"cancelled\", exitCode: null, promptSurfaced };\n    }\n\n    const exitCode = raced.exitCode;\n    if (exitCode !== 0) {\n      log(\"[paperclip] Device login command ended with a non-zero exit code.\");\n      return { outcome: \"failure\", exitCode, promptSurfaced };\n    }\n\n    if (onCredential && authPath) {\n      const authBytes = await driver.readFile(authPath);\n      await onCredential(authBytes);\n    }\n    log(\"[paperclip] Device login command ended successfully.\");\n    return { outcome: \"success\", exitCode, promptSurfaced };\n  } catch {\n    // Convert any driver error to a fixed, non-secret error. The original error\n    // may embed streamed bytes, so the runner never propagates its message.\n    throw new Error(\"device login failed: the sandbox login command errored.\");\n  } finally {\n    // Always dispose the driver. A dispose error must not leak or mask the\n    // result, so the runner swallows it and logs a fixed line.\n    try {\n      await driver.dispose();\n    } catch {\n      log(\"[paperclip] Device login: the sandbox dispose step errored.\");\n    }\n  }\n}\n","sourceCodeStart":178,"sourceCodeEnd":207,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapters/codex-local/src/server/device-login-runner.ts#L178-L207","documentation":"Thrown by the device-login runner's catch block when the injected SandboxLoginDriver rejects during execStreaming (running `codex login --device-auth`), readFile (reading the sandbox auth.json), or the race wrapper. The runner deliberately discards the original error message because sandbox stream bytes may carry the device code/URL/token, and rethrows a fixed non-secret message (Control 1 — secret handling).","triggerScenarios":"driver.execStreaming rejects (sandbox spawn failed, sandbox died mid-stream, network to sandbox dropped), or driver.readFile rejects (authPath missing/unreadable after a non-zero-exit was already handled), while running the device-login flow.","commonSituations":"Daytona sandbox quota exhausted or sandbox image unavailable; the auth.json path configured does not exist in the image; transient sandbox network failure during the login window; sandbox was deleted out from under the run.","solutions":["Retry the device login once — sandbox spawn failures are often transient.","Verify the sandbox image is reachable and the SandboxLoginDriver can spawn processes (check sandbox provider quota/health).","Confirm the authPath option points at the real Codex auth.json location inside the image (default ~/.codex/auth.json).","Inspect the non-secret progress lines (log callback) to see how far the run got before the failure."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// The runner hides the original error by design, so pre-flight the driver instead.\nasync function canSpawn(driver: SandboxLoginDriver): Promise<boolean> {\n  try {\n    const r = await driver.execStreaming(\"true\", () => {});\n    return r.exitCode === 0;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"let attempt = 0;\nlet result: DeviceLoginResult;\nwhile (true) {\n  try {\n    result = await runDeviceLogin(opts);\n    break;\n  } catch (e) {\n    if (e instanceof Error && /device login failed: the sandbox login command errored/.test(e.message) && attempt++ < 1) continue;\n    throw e;\n  }\n}\n// then inspect result.outcome for failure/timeout/cancelled distinctly","preventionTips":["Pre-flight the sandbox (spawn a no-op) before invoking the login command.","Confirm the authPath exists in the image before the run starts.","Keep the driver non-persistent so a bad sandbox is discarded, not reused.","Surface the fixed log lines to the operator since the error itself is non-descriptive."],"tags":["codex","device-login","sandbox","security","secret-handling"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}