{"record":{"id":"6788c28167e8375e","repo":"sipeed/picoclaw","slug":"login-password-must-be-at-least-8-characters","errorCode":null,"errorMessage":"Login password must be at least 8 characters.","messagePattern":"Login password must be at least 8 characters\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"web/frontend/src/components/config/config-page.tsx","lineNumber":308,"sourceCode":"    } finally {\n      setShowFactoryResetDialog(false)\n    }\n  }\n\n  const handleSave = async () => {\n    try {\n      setSaving(true)\n      const password = launcherForm.dashboardPassword.trim()\n      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 &&","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/web/frontend/src/components/config/config-page.tsx#L290-L326","documentation":"Validation error thrown in handleSave (web/frontend/src/components/config/config-page.tsx:308, message from i18n key pages.config.dashboard_password_min_length) when the trimmed password has fewer than 8 code points. Note the check is Array.from(password).length, which counts Unicode code points, not UTF-16 units — an emoji counts as 1 even though its .length is 2. Client-side mirror of the minimum length enforced by POST /api/auth/setup.","triggerScenarios":"Entering 1-7 characters (after trim) into a dirty dashboard password field and saving; multi-byte characters do not help since code points are counted.","commonSituations":"User attempts a short PIN-style password; password manager generated a 6-char password; user counts an emoji as two characters and is surprised it still fails.","solutions":["Choose a password of 8 or more characters (code points)","Use a generated passphrase from a password manager to satisfy length safely","Remember leading/trailing whitespace is stripped before counting"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const MIN = 8\nif (launcherPasswordDirty && Array.from(password).length < MIN) {\n  setFieldError(`Login password must be at least ${MIN} characters.`)\n  return\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handleSave()\n} catch (err) {\n  if (err instanceof Error) setError(err.message)\n}","preventionTips":["Show a live character counter on the password field","Match the client minimum to the backend /api/auth/setup rule so they never disagree","Remember count is in Unicode code points; do not rely on String.length near the boundary"],"tags":["validation","frontend","password","config","i18n","unicode"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}