{"record":{"id":"06ed4ff1939bc3fe","repo":"paperclipai/paperclip","slug":"createos-returned-an-invalid-resource-id","errorCode":null,"errorMessage":"CreateOS returned an invalid resource ID.","messagePattern":"CreateOS returned an invalid resource ID\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/plugins/sandbox-providers/createos/src/client.ts","lineNumber":28,"sourceCode":"    super(`CreateOS request failed (HTTP ${status})${operation ? ` during ${operation}` : \"\"}.`);\n  }\n}\n\nexport interface Sandbox {\n  id: string;\n  status?: string;\n}\n\nexport function object(value: unknown): Record<string, unknown> {\n  if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n    throw new Error(\"CreateOS returned an invalid response.\");\n  }\n  return value as Record<string, unknown>;\n}\n\nexport function identifier(value: unknown): string {\n  if (typeof value !== \"string\" || !/^[A-Za-z0-9_-]{1,200}$/.test(value)) {\n    throw new Error(\"CreateOS returned an invalid resource ID.\");\n  }\n  return value;\n}\n\nexport class CreateosClient {\n  readonly apiKey: string;\n  constructor(readonly config: CreateosConfig) {\n    this.apiKey = resolveApiKey(config);\n  }\n\n  async request(path: string, init: RequestInit = {}): Promise<Response> {\n    const signal = init.signal ?? AbortSignal.timeout(this.config.timeoutMs);\n    await waitForRequest(this.config.apiUrl, signal);\n    let response: Response;\n    try {\n      response = await fetch(`${this.config.apiUrl}/v1${path}`, {\n        ...init,\n        redirect: \"error\",","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/plugins/sandbox-providers/createos/src/client.ts#L10-L46","documentation":"`identifier()` validates resource IDs returned by (or passed to) the CreateOS API against `^[A-Za-z0-9_-]{1,200}$`. This error means the provider returned an id that is missing, not a string, or contains characters outside the allowed set (or exceeds 200 chars). The client throws it rather than passing a malformed id into URLs where it could enable injection or break routing.","triggerScenarios":"`createSandbox()` calling `identifier(data.id)` when the create response omits `id` or returns a non-string; `getSandbox()`/`destroySandbox()`/`upload()`/`transition()` calling `identifier(id)` with an id previously read from a bad source; a provider response echoing an empty string or an id containing slashes, dots, or whitespace.","commonSituations":"Provider API change renaming the id field (e.g. `sandboxId`); a stub/mock server returning placeholder ids; a sandbox id captured from logs or user input containing path characters; truncation of long ids by an intermediary.","solutions":["Inspect the create/get response `data` object and confirm the `id` field exists and is a string.","Ensure the id value came from a CreateOS response, not from user input or a differently-shaped upstream record.","Check for provider API version changes that renamed or restructured the id field.","Regenerate/recreate the sandbox; an empty or malformed id often indicates the create actually failed upstream.","If your own stored ids may be malformed, validate them with the same regex before calling client methods."],"exampleFix":"// before: passing through an unvetted id\nawait client.destroySandbox(someId);\n// after: validating first\nif (typeof someId !== \"string\" || !/^[A-Za-z0-9_-]{1,200}$/.test(someId)) {\n  throw new Error(\"Refusing to use malformed sandbox id.\");\n}\nawait client.destroySandbox(someId);","handlingStrategy":"validation","validationCode":"const ID_RE = /^[A-Za-z0-9_-]{1,200}$/;\nfunction assertValidId(id: unknown): asserts id is string {\n  if (typeof id !== \"string\" || !ID_RE.test(id)) throw new Error(\"Invalid sandbox id.\");\n}\nassertValidId(id);\nawait client.getSandbox(id);","typeGuard":"function isSandboxId(v: unknown): v is string {\n  return typeof v === \"string\" && /^[A-Za-z0-9_-]{1,200}$/.test(v);\n}","tryCatchPattern":"try {\n  await client.destroySandbox(id);\n} catch (e) {\n  if (e instanceof Error && e.message === \"CreateOS returned an invalid resource ID.\") {\n    // id came from a bad source; treat the record as corrupt and skip/recreate\n  } else throw e;\n}","preventionTips":["Store sandbox ids only from `createSandbox()` responses, never from logs or user input.","Validate persisted ids with the same regex at load time.","Watch for provider API changes that rename the `id` field in create responses.","Use strict TypeScript types (string) for ids end-to-end so non-strings fail at compile time."],"tags":["validation","identifier","api","sandbox-provider"],"backgroundTag":"invalid-identifier-format","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}