{"record":{"id":"f0e034bb069eb734","repo":"paperclipai/paperclip","slug":"createos-sandbox-identity-or-state-is-invalid","errorCode":null,"errorMessage":"CreateOS sandbox identity or state is invalid.","messagePattern":"CreateOS sandbox identity or state is invalid\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/client.ts","lineNumber":86,"sourceCode":"    }\n    return response;\n  }\n\n  async json(path: string, method = \"GET\", body?: unknown, signal?: AbortSignal): Promise<Record<string, unknown>> {\n    const response = await this.request(path, {\n      method,\n      ...(body !== undefined ? { body: JSON.stringify(body), headers: { \"Content-Type\": \"application/json\" } } : {}),\n      signal,\n    });\n    let envelope: Record<string, unknown>;\n    try { envelope = object(await response.json()); } catch { throw new Error(\"CreateOS returned invalid JSON.\"); }\n    if (envelope.status !== \"success\") throw new Error(\"CreateOS returned an unsuccessful response.\");\n    return object(envelope.data);\n  }\n\n  async getSandbox(id: string, signal?: AbortSignal): Promise<Sandbox> {\n    const data = await this.json(`/sandboxes/${identifier(id)}`, \"GET\", undefined, signal);\n    if (data.id !== id || typeof data.status !== \"string\") throw new Error(\"CreateOS sandbox identity or state is invalid.\");\n    return { id, status: data.status };\n  }\n\n  async createSandbox(signal: AbortSignal): Promise<Sandbox> {\n    const { shape, rootfs, region } = this.config;\n    const data = await this.json(\"/sandboxes\", \"POST\", {\n      shape,\n      ...(rootfs ? { rootfs } : {}),\n      ...(region ? { region } : {}),\n      ingress_enabled: false,\n      // The host owns lease release. Idle pause is not a command timeout or a\n      // guaranteed expiry, and could suspend a quiet active agent.\n    }, signal);\n    return { id: identifier(data.id) };\n  }\n\n  async destroySandbox(id: string): Promise<void> {\n    try { await this.json(`/sandboxes/${identifier(id)}`, \"DELETE\"); }","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/client.ts#L68-L104","documentation":"getSandbox fetches a sandbox from the CreateOS API and validates that the returned record matches the requested ID and carries a string status. The library throws this error when the response body fails either check, meaning the provider returned a sandbox record that cannot be trusted as the identity/state of the requested sandbox. It guards callers against acting on stale or mismatched API data.","triggerScenarios":"Calling getSandbox(id) when the CreateOS API returns a successful envelope whose data.id differs from the requested id, or whose data.status is missing or not a string (e.g. null status, snake_case key like sandbox_status, or an error-shaped object wrapped in a 200 response).","commonSituations":"Hitting a different CreateOS environment than configured (data belongs to another tenant so IDs never match), a proxy/gateway rewriting the response, a CreateOS API version change renaming the status field, or caching layers returning a different sandbox record.","solutions":["Log the returned data object and compare data.id to the requested id to find the mismatch source.","Verify apiUrl points at the correct CreateOS environment/tenant that actually owns this sandbox id.","Check the CreateOS API version; upgrade or pin the plugin if the response schema (id/status fields) changed.","Disable or audit any proxy/CDN between the plugin and CreateOS that could alter or substitute the response."],"exampleFix":"// before: assuming data matches\nconst data = await this.json(`/sandboxes/${identifier(id)}`, \"GET\", undefined, signal);\nif (data.id !== id || typeof data.status !== \"string\") throw new Error(\"CreateOS sandbox identity or state is invalid.\");\n// after: tolerate a wrapped/alternate payload before throwing\nconst data = await this.json(`/sandboxes/${identifier(id)}`, \"GET\", undefined, signal);\nconst record = data.sandbox ?? data;\nif (record.id !== id || typeof record.status !== \"string\") throw new Error(`CreateOS returned sandbox ${record.id} (status: ${String(record.status)}) for requested id ${id}.`);","handlingStrategy":"validation","validationCode":"function assertSandboxResponse(data, requestedId) {\n  if (!data || typeof data !== \"object\") throw new Error(\"CreateOS response is not an object\");\n  if (typeof data.id !== \"string\" || data.id !== requestedId) throw new Error(`CreateOS returned id ${data.id}, expected ${requestedId}`);\n  if (typeof data.status !== \"string\") throw new Error(`CreateOS returned non-string status: ${typeof data.status}`);\n  return true;\n}","typeGuard":"function isSandbox(v: unknown): v is { id: string; status: string } {\n  return typeof v === \"object\" && v !== null &&\n    typeof (v as any).id === \"string\" && typeof (v as any).status === \"string\";\n}","tryCatchPattern":"try {\n  const sandbox = await provider.getSandbox(id);\n} catch (err) {\n  if (err.message.includes(\"identity or state is invalid\")) {\n    logger.warn({ id }, \"CreateOS sandbox response failed identity check; refetching or recreating\");\n    sandbox = await recreateSandbox();\n  } else throw err;\n}","preventionTips":["Pin the CreateOS API version and verify response schema after provider upgrades.","Log the raw response body on mismatch to diagnose tenant/environment drift.","Avoid proxies that rewrite API responses between the plugin and CreateOS.","Always cross-check data.id against the requested id before caching sandbox records."],"tags":["api","validation","unexpected-response-shape"],"backgroundTag":"unexpected-response-shape","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}