{"record":{"id":"d27a783282dd458c","repo":"musistudio/claude-code-router","slug":"path-is-required","errorCode":null,"errorMessage":"path is required.","messagePattern":"path is required\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/electron/bundled-plugins/claude-design/index.cjs","lineNumber":1283,"sourceCode":"  const paths = Array.isArray(body?.paths) ? body.paths : [];\n  let deleted = 0;\n  for (const filePath of paths) {\n    deleted += deleteProjectFileByPath(runtime, projectId, filePath);\n  }\n  runtime.store.persist();\n  return {\n    deleted,\n    paths: paths.map((item) => sanitizeProjectFilePath(item)).filter(Boolean),\n    projectId,\n    project_id: projectId\n  };\n}\n\nfunction recordDesignSyncJsonAsset(runtime, body) {\n  const projectId = designSyncJsonProjectId(body);\n  const filePath = sanitizeProjectFilePath(body?.path || \"\");\n  if (!filePath) {\n    throw new Error(\"path is required.\");\n  }\n  const name = stringValue(body?.name) || filePath;\n  const uuid = assetUuid(projectId, name, filePath);\n  const asset = {\n    chat_id: stringValue(body?.chatId) || stringValue(body?.chat_id) || \"\",\n    name,\n    path: filePath,\n    project_id: projectId,\n    section: stringValue(body?.section) || stringValue(body?.group) || \"\",\n    status: stringValue(body?.status) || \"recorded\",\n    subtitle: stringValue(body?.subtitle) || \"\",\n    uuid,\n    viewport: isRecord(body?.viewport) ? body.viewport : undefined\n  };\n  upsertGenericRecord(runtime.store, \"assets\", uuid, name, runtime.me.defaultModelId, asset);\n  return {\n    asset,\n    ok: true,","sourceCodeStart":1265,"sourceCodeEnd":1301,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/electron/bundled-plugins/claude-design/index.cjs#L1265-L1301","documentation":"Thrown by recordDesignSyncJsonAsset when sanitizeProjectFilePath(body.path) returns an empty result — i.e. the provided path is empty or is stripped entirely during sanitization. An asset record requires a valid project-relative file path.","triggerScenarios":"Calling the asset endpoint with path omitted, set to \"\", \".\", \"/\", or a value that sanitization reduces to empty (e.g. only traversal segments like \"../..\").","commonSituations":"Client derives the path from a filename variable that is undefined; user saved an asset before choosing a location; aggressive path sanitization stripping leading slashes or dot segments leaving nothing.","solutions":["Provide a non-empty relative path like \"assets/icon.png\"","Avoid absolute paths and traversal segments; use project-relative paths","Default the path from the asset name when the caller has none: path || `${name}.svg`"],"exampleFix":"// before\n{ projectId: \"proj_123\", path: \"\", name: \"hero\" }\n\n// after\n{ projectId: \"proj_123\", path: \"assets/hero.png\", name: \"hero\" }","handlingStrategy":"validation","validationCode":"if (!body?.path || sanitize(body.path) === \"\") body.path = `${body?.name || \"asset\"}.svg`;","typeGuard":"function hasNonEmptySanitizedPath(path: unknown): path is string {\n  return typeof path === \"string\" && path.trim() !== \"\" && !/^\\.{0,2}$/.test(path.trim());\n}","tryCatchPattern":"try { recordDesignSyncJsonAsset(runtime, body); } catch (e) { if (e instanceof Error && e.message === \"path is required.\") return respond(400, e.message); throw e; }","preventionTips":["Derive path from asset name as a fallback","Validate path client-side with the same sanitization rules","Block empty/traversal-only paths at the form layer"],"tags":["validation","missing-parameter","path-sanitization","design-sync"],"backgroundTag":"missing-required-parameter","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}