JuliusBrussee/caveman · error
artifactId is required
Error message
artifactId is required
What it means
Synchronous input validation at the top of artifactGet: the artifactId argument must be a non-empty, non-whitespace string, otherwise a plain Error("artifactId is required") is thrown before any network call is made. This is a fail-fast guard so callers get an immediate programming-error signal instead of a confusing 404 from the server.
Solutions
- Validate the artifact ID before calling: if (typeof id !== 'string' || id.trim() === '') throw new Error(...)
- Trace where the ID originates and fix the upstream producer that left it empty
- Use TypeScript strict mode / non-null assertions correctly so optional ID fields cannot flow through unchecked
- Add a unit test covering the empty-ID path of the wrapper function you call
Example fix
// before
const artifact = await sdk.getArtifact(record.artifactId); // record.artifactId is ''
// after
if (typeof record.artifactId !== 'string' || record.artifactId.trim() === '') {
throw new Error(`missing artifactId on record ${record.id}`);
}
const artifact = await sdk.getArtifact(record.artifactId); Defensive patterns
Strategy: validation
Validate before calling
function requireArtifactId(id: unknown): string { if (typeof id !== 'string' || id.trim() === '') throw new Error('artifactId is required'); return id; } Type guard
const hasArtifactId = (v: unknown): v is { artifactId: string } => typeof v === 'object' && v !== null && typeof (v as any).artifactId === 'string' && (v as any).artifactId.trim() !== ''; Try / catch
try { const a = await sdk.getArtifact(id, wf); } catch (e) { if (e instanceof Error && e.message === 'artifactId is required') throw new Error(`upstream record missing artifactId: ${JSON.stringify(record).slice(0, 200)}`); throw e; } Prevention
- Validate IDs at the boundary where records are produced/consumed
- Enable TypeScript strict null checks and avoid any-typed ID flows
- Fail fast with context (record id) when an upstream field is missing
- Unit-test the empty/whitespace ID path of your wrapper functions
When it happens
Trigger: Calling an SDK method that internally fetches an artifact while passing undefined, null, an empty string "", or a whitespace-only string as the artifact identifier — typically when the ID comes from an upstream API response field or a variable that was never populated.
Common situations: Destructuring an artifact reference from a prior response that omitted the id field; template strings like `art-${n}` with n undefined; TypeScript types bypassed via any/as-casts; optional IDs from config files left blank.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- arm must be or
- assemble requires model and sessionId
- cannot supersede with empty text
- cave artifact response missing artifact_id
- cave checkpoint response missing source_ref or messages
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/29bc63375ccf13ee.
Report an issue: GitHub.
Appendix: source
Thrown at packages/sdk/typescript/src/index.ts:2144
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) {
discardResponse(response);
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 {View on GitHub (pinned to 3ee70a1026)