JuliusBrussee/caveman · error
artifactId is required
Error message
artifactId is required
What it means
Thrown by artifactGet() in the TypeScript SDK when the artifactId argument is not a string or is empty/whitespace-only. It is a local client-side guard fired before any network request to GET /sdk/v1/artifacts/{id}. The SDK refuses to build a URL from an unusable identifier.
Source
Thrown at packages/sdk/typescript/src/index.ts:2077
try {
if (typeof response.text === "function") {
decoded = JSON.parse(await response.text());
} else if (typeof response.json === "function") {
decoded = await response.json();
} else {
throw new Error("missing response decoder");
}
} catch {
throw new CaveRequestError(response.status, path, "cave response was not valid JSON");
}
if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded)) {
throw new CaveRequestError(response.status, path, "cave response must be a JSON object");
}
return decoded as Record<string, unknown>;
}
async function artifactGet(cave: Cave, artifactId: string, workflow: string, trace: TraceContext): Promise<unknown> {
if (typeof artifactId !== "string" || artifactId.trim() === "") throw new Error("artifactId is required");
const path = `/sdk/v1/artifacts/${encodeURIComponent(artifactId)}`;
const response = await caveFetch(cave, `${cave.options.baseURL}${path}`, {
method: "GET",
headers: headers(cave, workflow, undefined, undefined, trace)
});
if (!response.ok) throw new CaveRequestError(response.status, path, `cave request failed (${response.status})`);
try {
return JSON.parse(await response.text());
} catch {
throw new CaveRequestError(response.status, path, "cave artifact was not valid JSON");
}
}
function headers(cave: Cave, workflow: string, upstreamKey?: string, hint?: Record<string, unknown>, trace?: TraceContext) {
return {
"content-type": "application/json",
authorization: `Bearer ${cave.options.apiKey}`,
"x-cave-agent": cave.options.agent,View on GitHub (pinned to 27d5a3981a)
Solutions
- Pass a non-empty string artifact id exactly as returned by artifacts.page() / the gateway
- If the id comes from untrusted data, trim and validate it before calling get()
- Type the id as string at call sites so the compiler rejects undefined at build time
Example fix
// before
const art = await trace.artifacts.get(resp.artifact_id); // undefined if field absent
// after
const id = resp.artifact_id;
if (typeof id !== "string" || id.trim() === "") throw new Error("no artifact id in response");
const art = await trace.artifacts.get(id); Defensive patterns
Strategy: validation
Validate before calling
function isArtifactId(v) {
return typeof v === "string" && v.trim() !== "";
}
if (!isArtifactId(id)) throw new TypeError("artifact id missing"); Type guard
function isArtifactId(v) {
return typeof v === "string" && v.trim().length > 0;
} Prevention
- Type artifact ids as string (not any) everywhere they flow
- Validate ids at the boundary where they enter your code (API responses, queues) instead of at the SDK call
When it happens
Trigger: Calling CaveTrace.artifacts.get(id) (which delegates to artifactGet) with undefined, null, a number, an array, or an empty/whitespace string — typically the result of destructuring an id from an object that never had one, or using a checkpoint source_ref instead of an artifact id.
Common situations: Reading an id from an API response that renamed the field; passing a handle from a failed artifacts.page() call; default parameters evaluating to undefined; ids from JSON.parse typed loosely as any.
Related errors
- cave_breaker_threshold_invalid
- caveman agent: subagent maxCalls must be a positive integer
- caveman agent: file path is required
- caveman agent: unknown tool effect ${JSON.stringify(options.
- withTask: a callback is required
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/29bc63375ccf13ee.
Report an issue: GitHub.