musistudio/claude-code-router · error · Error

projectId is required.

Error message

projectId is required.

What it means

Thrown by getDesignSyncJsonProject in the claude-design bundled plugin when neither `projectId` nor `project_id` is present (or both are empty strings) in the request body. The design-sync JSON handler needs a project identifier to look up the Omelette project.

Source

Thrown at packages/electron/bundled-plugins/claude-design/index.cjs:1156

    introText: stringValue(body?.introText) || stringValue(body?.intro_text),
    name: stringValue(body?.name) || "Untitled design system",
    templateId: stringValue(body?.templateId) || stringValue(body?.template_id),
    templateTitle: stringValue(body?.templateTitle) || stringValue(body?.template_title),
    type: normalizeDesignSyncProjectTypeFilter(body?.type ?? body?.projectType ?? body?.project_type)
  });
  const projectId = project.projectId || project.uuid;
  return {
    name: project.name,
    project: designSyncJsonProjectPayload(runtime, getOmeletteProject(runtime, projectId)),
    projectId,
    project_id: projectId
  };
}

function getDesignSyncJsonProject(runtime, body) {
  const projectId = stringValue(body?.projectId) || stringValue(body?.project_id);
  if (!projectId) {
    throw new Error("projectId is required.");
  }
  const project = designSyncJsonProjectPayload(runtime, getOmeletteProject(runtime, projectId));
  return {
    project,
    ...project
  };
}

function listDesignSyncJsonFiles(runtime, body) {
  const projectId = designSyncJsonProjectId(body);
  const directory = sanitizeProjectFilePath(body?.path || "");
  const depth = numberValue(body?.depth) ?? 1;
  const offset = Math.max(0, numberValue(body?.offset) ?? 0);
  const filter = stringValue(body?.filter);
  const allEntries = listProjectDirectoryEntries(runtime, projectId, directory, depth, filter);
  const limit = 200;
  const entries = allEntries.slice(offset, offset + limit);
  return {

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Include projectId (or project_id) as a non-empty string in the request body
  2. Fetch the project list first to obtain a valid id if unknown
  3. Check for typos in the key name (projectId vs project_id vs id)

Example fix

// before
body = { name: "My Project" }

// after
body = { projectId: "proj_123", name: "My Project" }
Defensive patterns

Strategy: validation

Validate before calling

const projectId = body?.projectId || body?.project_id;
if (!projectId) throw new ValidationError("projectId", "required before calling design sync");

Type guard

function hasProjectId(body: unknown): body is { projectId: string } {
  const b = body as Record<string, unknown>;
  return typeof (b?.projectId ?? b?.project_id) === "string" && (b.projectId ?? b.project_id) !== "";
}

Try / catch

try { getDesignSyncJsonProject(runtime, body); } catch (e) { if (e instanceof Error && e.message === "projectId is required.") return respond(400, { error: e.message }); throw e; }

Prevention

When it happens

Trigger: POSTing to the design sync JSON endpoint with a body that omits projectId/project_id, passes an empty string, or uses a different key name (e.g. `id`).

Common situations: Client built the request from a partial config where the project was never created; key-name mismatch between snake_case and camelCase clients; project deleted and the caller lost track of its id.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/08528c199dbc6010. Report an issue: GitHub.