{"record":{"id":"3aceb500dfb62905","repo":"sipeed/picoclaw","slug":"workspace-path-is-required","errorCode":null,"errorMessage":"Workspace path is required.","messagePattern":"Workspace path is required\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"web/frontend/src/components/config/config-page.tsx","lineNumber":317,"sourceCode":"      const confirm = launcherForm.dashboardPasswordConfirm.trim()\n      if (launcherPasswordDirty) {\n        if (!password) {\n          throw new Error(t(\"pages.config.dashboard_password_required\"))\n        }\n        if (password !== confirm) {\n          throw new Error(t(\"pages.config.dashboard_password_mismatch\"))\n        }\n        if (Array.from(password).length < 8) {\n          throw new Error(t(\"pages.config.dashboard_password_min_length\"))\n        }\n      }\n\n      if (configDirty) {\n        const workspace = form.workspace.trim()\n        const dmScope = form.dmScope.trim()\n\n        if (!workspace) {\n          throw new Error(\"Workspace path is required.\")\n        }\n        if (!dmScope) {\n          throw new Error(\"Session scope is required.\")\n        }\n\n        if (\n          form.mcpEnabled &&\n          form.mcpDiscoveryEnabled &&\n          !form.mcpDiscoveryUseBM25 &&\n          !form.mcpDiscoveryUseRegex\n        ) {\n          throw new Error(\n            \"MCP discovery requires at least one search method (BM25 or regex).\",\n          )\n        }\n\n        const maxTokens = parseIntField(form.maxTokens, \"Max tokens\", {\n          min: 1,","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/web/frontend/src/components/config/config-page.tsx#L299-L335","documentation":"Validation error thrown in handleSave (web/frontend/src/components/config/config-page.tsx:317) when the config section is dirty and the workspace path trims to empty. The workspace is a required field of the gateway config PATCH built by handleSave, so an empty value aborts the save before any network call.","triggerScenarios":"Clearing the workspace input (or filling it with whitespace) and saving while configDirty; also if form state was initialized empty because /api/config returned a config without a workspace value.","commonSituations":"User clears the field intending to reset to a default; config loaded from a fresh install has no workspace set; user pastes only spaces.","solutions":["Enter an absolute directory path for the workspace, e.g. /home/user/projects or C:\\work","If unsure of the expected default, check the raw config page or backend docs for the default workspace value and re-enter it","Verify the field is not just whitespace — the value is trimmed before the check"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const workspace = form.workspace.trim()\nif (configDirty && !workspace) {\n  setFieldError(\"Workspace path is required.\")\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handleSave()\n} catch (err) {\n  if (err instanceof Error) setError(err.message)\n}","preventionTips":["Mark the workspace input as required in the UI","Default the field from the loaded config so it is never empty on a fresh form","Consider a directory picker so users cannot type an empty value"],"tags":["validation","frontend","config","workspace"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}