{"record":{"id":"240c8f4260514ec8","repo":"musistudio/claude-code-router","slug":"project-id-and-path-are-required-to-write-a-claude","errorCode":null,"errorMessage":"project_id and path are required to write a Claude Design file.","messagePattern":"project_id and path are required to write a Claude Design file\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/electron/bundled-plugins/claude-design/index.cjs","lineNumber":9007,"sourceCode":"  }\n  return queryRows(\n    runtime.store.database,\n    \"SELECT project_id, path, created_at, updated_at, content_type, body_base64, version FROM claude_design_files WHERE project_id = ? AND path = ? LIMIT 1\",\n    [normalizedProjectId, normalizedPath]\n  )[0];\n}\n\nfunction getProjectFileText(runtime, projectId, filePath) {\n  const row = getProjectFileRow(runtime, projectId, filePath);\n  return row ? Buffer.from(row.body_base64 || \"\", \"base64\").toString(\"utf8\") : \"\";\n}\n\nfunction upsertProjectFile(runtime, projectId, filePath, body, contentType) {\n  const address = normalizeProjectFileAddress(runtime, projectId, filePath || \"\");\n  const normalizedProjectId = address.projectId;\n  const normalizedPath = address.path;\n  if (!normalizedProjectId || !normalizedPath) {\n    throw new Error(\"project_id and path are required to write a Claude Design file.\");\n  }\n  const now = new Date().toISOString();\n  const existing = getProjectFileRow(runtime, normalizedProjectId, normalizedPath);\n  const version = existing ? Number(existing.version || 0) + 1 : 1;\n  runtime.store.database.run(\n    \"INSERT OR REPLACE INTO claude_design_files (project_id, path, created_at, updated_at, content_type, body_base64, version) VALUES (?, ?, ?, ?, ?, ?, ?)\",\n    [\n      normalizedProjectId,\n      normalizedPath,\n      existing?.created_at || now,\n      now,\n      contentType || guessContentType(normalizedPath),\n      Buffer.isBuffer(body) ? body.toString(\"base64\") : Buffer.from(String(body || \"\"), \"utf8\").toString(\"base64\"),\n      version\n    ]\n  );\n  return getProjectFileRow(runtime, normalizedProjectId, normalizedPath);\n}","sourceCodeStart":8989,"sourceCodeEnd":9025,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/electron/bundled-plugins/claude-design/index.cjs#L8989-L9025","documentation":"Validation error from upsertProjectFile when normalizing the (projectId, filePath) pair yields an empty project id or path. The write goes through normalizeProjectFileAddress, so inputs that reduce to empty strings fail before the SQLite INSERT OR REPLACE.","triggerScenarios":"Calling the write-file API with missing project_id, missing/empty path, whitespace-only path, or an address string that normalizes to an empty path segment.","commonSituations":"UI form submitted without selecting a project, path trimmed to empty, caller passing a directory address instead of a file path, or constructing the address string with a bad separator.","solutions":["Ensure project_id is a non-empty valid id from project creation","Ensure path is a non-empty relative file path (e.g. designs/home.json)","Validate/trim inputs in the caller before invoking the API","Log the normalized address to catch separator/format bugs"],"exampleFix":"// before\nawait upsertProjectFile(runtime, '', '', body, 'application/json');\n\n// after\nif (!projectId || !filePath?.trim()) throw new TypeError('projectId and filePath are required');\nawait upsertProjectFile(runtime, projectId, filePath.trim(), body, 'application/json');","handlingStrategy":"validation","validationCode":"if (!String(projectId ?? '').trim() || !String(filePath ?? '').trim()) {\n  throw new TypeError('projectId and filePath must be non-empty');\n}","typeGuard":"function isValidFileAddress(projectId: unknown, filePath: unknown): projectId is string {\n  return typeof projectId === 'string' && projectId.trim() !== ''\n    && typeof filePath === 'string' && filePath.trim() !== '';\n}","tryCatchPattern":"catch (e) { if (/project_id and path are required/.test(e.message)) return { ok: false, error: 'invalid_input' }; throw e; }","preventionTips":["Require and trim both fields in UI forms","Validate address format before normalizeProjectFileAddress","Add JSON-schema validation at the API boundary"],"tags":["validation","required-field","sqlite","file-write"],"backgroundTag":"missing-required-parameter","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}