{"record":{"id":"8a8464eea37985c8","repo":"nexu-io/open-design","slug":"no-projects-on-this-daemon","errorCode":null,"errorMessage":"no projects on this daemon","messagePattern":"no projects on this daemon","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"apps/daemon/src/mcp.ts","lineNumber":2970,"sourceCode":"      'project arg omitted and Open Design has no active project. The active context expires about 5 minutes after the last user interaction with Open Design - the user may need to click into a project to wake it up. Otherwise pass project=\"<id-or-name>\".',\n    );\n  }\n  return { id: active.projectId, resolved: null, active };\n}\n\nasync function resolveProjectId(\n  baseUrl: string,\n  arg: unknown,\n  headers?: Record<string, string>,\n): Promise<ResolvedProject> {\n  if (typeof arg !== 'string' || !arg) {\n    throw new Error('project is required (string).');\n  }\n  if (UUID_RE.test(arg)) return { id: arg, name: arg, source: 'uuid' as const };\n\n  const list = await fetchProjectList(baseUrl, headers);\n  if (list.length === 0) {\n    throw new Error('no projects on this daemon');\n  }\n\n  const lower = arg.toLowerCase();\n  const norm = (s: unknown): string =>\n    String(s || '')\n      .toLowerCase()\n      .replace(/\\s*\\(\\d+\\)\\s*$/, '')\n      .replace(/[\\s_-]+/g, '-');\n  const target = norm(arg);\n\n  const idMatch = list.find((p) => p.id === arg);\n  if (idMatch) return { id: idMatch.id, name: idMatch.name, source: 'id' as const };\n\n  const exact = list.filter((p) => String(p.name || '').toLowerCase() === lower);\n  if (exact.length === 1) { const p = exact[0]!; return { id: p.id, name: p.name, source: 'exact' as const }; }\n\n  const slugged = list.filter((p) => norm(p.name) === target);\n  if (slugged.length === 1) { const p = slugged[0]!; return { id: p.id, name: p.name, source: 'slug' as const }; }","sourceCodeStart":2952,"sourceCodeEnd":2988,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/mcp.ts#L2952-L2988","documentation":"Thrown by resolveProjectId after fetchProjectList returned an empty array. The daemon has no projects at all, so no name or UUID can resolve. This is a state error, not a typo: the workspace is empty.","triggerScenarios":"Fresh daemon install with no projects created; all projects deleted; pointing at a data root (OD_DATA_DIR) that is empty or newly initialized; misconfigured namespace isolating an empty project set.","commonSituations":"First-time setup; CI using a clean OD_DATA_DIR; tools-dev --namespace pointing at an unused namespace; the user imported a folder but it registered under a different data root.","solutions":["Create a project first via the Open Design UI or the project MCP/CLI tool, then retry.","Confirm you are pointing at the right daemon and OD_DATA_DIR (check tools-dev status and namespace).","If projects should exist, verify the data root the daemon resolved matches where they live.","For imported-folder projects, confirm metadata.baseDir points at the imported location."],"exampleFix":"// before: daemon has zero projects\nrunStart({ project: \"anything\" })\n// after: create one first\nawait createProject({ title: \"my-deck\" });\nrunStart({ project: \"my-deck\" })","handlingStrategy":"validation","validationCode":"const list = await fetchProjectList(baseUrl, headers);\nif (list.length === 0) throw new Error('create a project before invoking run tools');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Seed the daemon with at least one project during setup.","Verify OD_DATA_DIR/namespace points at the populated data root.","List projects as a precondition check before resolving."],"tags":["mcp","project-resolution","state","setup"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}