paperclipai/paperclip · error
CreateOS returned an invalid resource ID.
Error message
CreateOS returned an invalid resource ID.
What it means
`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.
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.
Example fix
// before: passing through an unvetted id
await client.destroySandbox(someId);
// after: validating first
if (typeof someId !== "string" || !/^[A-Za-z0-9_-]{1,200}$/.test(someId)) {
throw new Error("Refusing to use malformed sandbox id.");
}
await client.destroySandbox(someId); Defensive patterns
Strategy: validation
Validate before calling
const ID_RE = /^[A-Za-z0-9_-]{1,200}$/;
function assertValidId(id: unknown): asserts id is string {
if (typeof id !== "string" || !ID_RE.test(id)) throw new Error("Invalid sandbox id.");
}
assertValidId(id);
await client.getSandbox(id); Type guard
function isSandboxId(v: unknown): v is string {
return typeof v === "string" && /^[A-Za-z0-9_-]{1,200}$/.test(v);
} Try / catch
try {
await client.destroySandbox(id);
} catch (e) {
if (e instanceof Error && e.message === "CreateOS returned an invalid resource ID.") {
// id came from a bad source; treat the record as corrupt and skip/recreate
} else throw e;
} Prevention
- 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.
When it happens
Trigger: `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.
Common situations: 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.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- CreateOS returned an invalid response.
- CreateOS returned an unsuccessful response.
- CreateOS returned invalid JSON.
- CreateOS sandbox identity or state is invalid.
- device-login promotion: the account identifier cannot form…
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/06ed4ff1939bc3fe.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugins/sandbox-providers/createos/src/client.ts:28
super(`CreateOS request failed (HTTP ${status})${operation ? ` during ${operation}` : ""}.`);
}
}
export interface Sandbox {
id: string;
status?: string;
}
export function object(value: unknown): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error("CreateOS returned an invalid response.");
}
return value as Record<string, unknown>;
}
export function identifier(value: unknown): string {
if (typeof value !== "string" || !/^[A-Za-z0-9_-]{1,200}$/.test(value)) {
throw new Error("CreateOS returned an invalid resource ID.");
}
return value;
}
export class CreateosClient {
readonly apiKey: string;
constructor(readonly config: CreateosConfig) {
this.apiKey = resolveApiKey(config);
}
async request(path: string, init: RequestInit = {}): Promise<Response> {
const signal = init.signal ?? AbortSignal.timeout(this.config.timeoutMs);
await waitForRequest(this.config.apiUrl, signal);
let response: Response;
try {
response = await fetch(`${this.config.apiUrl}/v1${path}`, {
...init,
redirect: "error",View on GitHub (pinned to 3f1d897a7c)