{"record":{"id":"ff004f9b70a702a5","repo":"different-ai/openwork","slug":"project-dir-is-required","errorCode":null,"errorMessage":"project_dir is required","messagePattern":"project_dir is required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/runtime.mjs","lineNumber":2266,"sourceCode":"    const installDir = path.join(app.getPath(\"home\"), \".opencode\", \"bin\");\n    const command = await pinnedOpencodeInstallCommand();\n    const result = await runShellCommand(\"bash\", [\"-lc\", command], {\n      env: { ...(await buildChildEnv()), OPENCODE_INSTALL_DIR: installDir },\n      timeoutMs: 180_000,\n    });\n    return {\n      ok: result.status === 0,\n      status: result.status,\n      stdout: result.stdout,\n      stderr: result.stderr,\n    };\n  }\n\n  async function opencodeMcpAuth(projectDir, serverName) {\n    const safeProjectDir = String(projectDir ?? \"\").trim();\n    const safeServerName = String(serverName ?? \"\").trim();\n    if (!safeProjectDir) {\n      throw new Error(\"project_dir is required\");\n    }\n    if (!safeServerName) {\n      throw new Error(\"server_name is required\");\n    }\n\n    const program = resolveBinary(\"opencode\");\n    if (!program) {\n      throw new Error(\"Failed to locate opencode.\");\n    }\n\n    const result = await runShellCommand(program, [\"mcp\", \"auth\", safeServerName], {\n      cwd: safeProjectDir,\n      env: await buildChildEnv(),\n      timeoutMs: 120_000,\n    });\n    return {\n      ok: result.status === 0,\n      status: result.status,","sourceCodeStart":2248,"sourceCodeEnd":2284,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/runtime.mjs#L2248-L2284","documentation":"This error is thrown by the `opencodeMcpAuth` helper in the Electron runtime before it shells out to the `opencode` binary for MCP server authentication. The function requires a non-empty `projectDir` because the child process runs with it as its working directory (the project scope for MCP auth). When the argument is missing, null, or whitespace-only after trimming, it fails fast with this message instead of spawning a process in the wrong directory.","triggerScenarios":"Calling `opencodeMcpAuth(undefined, ...)`, `opencodeMcpAuth(null, ...)`, `opencodeMcpAuth(\"\", ...)` or `opencodeMcpAuth(\"   \", ...)` — i.e. the projectDir argument is absent, empty, or whitespace-only.","commonSituations":"IPC handlers invoked from the renderer before a project/folder has been opened; a stale or corrupted UI state where the workspace path was never set; callers passing an untrimmed blank string from config; refactoring that renamed the parameter without updating all call sites.","solutions":["Ensure a project directory is resolved before calling opencodeMcpAuth (e.g. from app state or dialog result)","Trim and validate the projectDir argument at the call site before invoking","Guard the IPC/invocation flow so the MCP auth action is disabled when no project is open"],"exampleFix":"// before\nawait opencodeMcpAuth(state.projectDir, serverName);\n// after\nif (!state.projectDir?.trim()) throw new Error('Open a project first');\nawait opencodeMcpAuth(state.projectDir, serverName);","handlingStrategy":"validation","validationCode":"function hasProjectDir(dir) {\n  return typeof dir === 'string' && dir.trim().length > 0;\n}","typeGuard":"function isNonEmptyString(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  await opencodeMcpAuth(projectDir, serverName);\n} catch (e) {\n  if (e.message === 'project_dir is required') {\n    promptUserToOpenProject();\n  } else throw e;\n}","preventionTips":["Disable MCP auth UI actions until a project is open","Trim inputs at boundaries before passing to runtime helpers","Centralize project-dir retrieval in one accessor that guarantees a value or throws earlier"],"tags":["argument-validation","electron","mcp"],"backgroundTag":"missing-required-argument","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}