{"record":{"id":"eb5dcb60f5f98f18","repo":"paperclipai/paperclip","slug":"prepare-local-sign-in-before-connecting","errorCode":null,"errorMessage":"Prepare local sign-in before connecting.","messagePattern":"Prepare local sign-in before connecting\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/src/components/ai-connections/useLocalAiLogin.ts","lineNumber":88,"sourceCode":"      cancelled = true;\n      clearTimeout(timer);\n      window.removeEventListener(\"focus\", onFocus);\n      document.removeEventListener(\"visibilitychange\", onFocus);\n      // Navigation is not cancellation. The server resumes this bounded attempt\n      // when the user returns and reaps abandoned attempts after expiry. Deleting\n      // here made copied CODEX_HOME commands point at nonexistent directories.\n    };\n  }, [companyId, active, isolated, target, generation]);\n  return {\n    isolated,\n    command: attempt?.command,\n    status,\n    preparing: active && !status && !error,\n    error,\n    retry: () => { restartRequested.current = true; cancelCurrent(); setGeneration((value) => value + 1); },\n    connect: (input = intent) => {\n      if (!companyId) throw new Error(\"Choose a company before connecting.\");\n      if (isolated && !attempt) throw new Error(\"Prepare local sign-in before connecting.\");\n      return aiConnectionsApi.connectLocal(companyId, { ...input, ...(attempt ? { localSessionId: attempt.sessionId } : {}) });\n    },\n  };\n}\n","sourceCodeStart":70,"sourceCodeEnd":93,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/ui/src/components/ai-connections/useLocalAiLogin.ts#L70-L93","documentation":"In `isolated` mode, connect() must reuse a prepared local sign-in session: the flow first prepares an attempt (getting a `sessionId`), then connects with `localSessionId`. Connecting with no prepared attempt would start a local sign-in outside the isolated session contract, so this guard throws.","triggerScenarios":"Calling `connect()` while `isolated` is true and `attempt` is null — i.e. skipping the prepare step or the prepare attempt failed/was cancelled before connect was clicked.","commonSituations":"User clicks Connect before the local sign-in preparation finished; preparation errored and UI still allowed connect; `retry()` bumped the generation and cleared the attempt, then connect was called.","solutions":["Await a successful preparation (non-null `attempt`/status ready) before enabling the Connect button.","If preparation failed, use the returned `retry()` to restart it instead of calling connect directly.","In non-isolated contexts, verify the `isolated` flag is intentional; it changes the required call order."],"exampleFix":"// before\nonClick={() => connect()}\n// after\nonClick={() => { if (isolated && !attempt) retry(); else connect(); }}","handlingStrategy":"validation","validationCode":"if (isolated && !attempt) { retry(); return; } await connect();","typeGuard":"const isPrepared = (a: unknown): a is { sessionId: string } => !!a && typeof (a as any).sessionId === 'string';","tryCatchPattern":"try { await connect(); } catch (e) { if (/Prepare local sign-in/.test(e.message)) retry(); }","preventionTips":["Gate the Connect button on prepared state (attempt !== null).","Show preparation progress so users wait for readiness.","Auto-call retry() when a generation bump invalidated the attempt."],"tags":["react","state-machine","ui-flow"],"backgroundTag":"invalid-state-transition","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}