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
- Include projectId (or project_id) as a non-empty string in the request body
- Fetch the project list first to obtain a valid id if unknown
- 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
- Set projectId in one shared request-builder
- Reject requests early in middleware when projectId is missing
- Accept both projectId and project_id in custom clients
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
- path is required.
- File not found: ${filePath}
- The CCR artifact endpoint returned a non-media content type.
- The CCR media artifact exceeds the inline preview size limit
- Compressed CCR media artifacts are not accepted for inline p
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/08528c199dbc6010.
Report an issue: GitHub.