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

  1. Validate the artifact ID before calling: if (typeof id !== 'string' || id.trim() === '') throw new Error(...)
  2. Trace where the ID originates and fix the upstream producer that left it empty
  3. Use TypeScript strict mode / non-null assertions correctly so optional ID fields cannot flow through unchecked
  4. 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

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


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)