{"record":{"id":"c143cea1a516b161","repo":"tinyhumansai/openhuman","slug":"request-timed-out-please-try-again","errorCode":null,"errorMessage":"Request timed out. Please try again.","messagePattern":"Request timed out\\. Please try again\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/services/api/authApi.ts","lineNumber":40,"sourceCode":"\n  try {\n    const versionHeaders = await getClientVersionHeaders();\n    const response = await fetch(`${backendUrl}/auth/email/send-link`, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json', ...versionHeaders },\n      body: JSON.stringify({ email, frontendRedirectUri }),\n      signal: controller.signal,\n    });\n    if (!response.ok) {\n      const body = (await response.json().catch(() => ({}))) as { error?: string };\n      throw new Error(body.error ?? `Failed to send magic link (${response.status})`);\n    }\n  } catch (error) {\n    if (\n      (error instanceof DOMException && error.name === 'AbortError') ||\n      (error instanceof Error && error.name === 'AbortError')\n    ) {\n      throw new Error('Request timed out. Please try again.');\n    }\n    throw error;\n  } finally {\n    window.clearTimeout(timeoutId);\n  }\n}\n\n/**\n * Consume a verified login token and return the JWT.\n * Works for both Telegram and OAuth login tokens.\n * POST /telegram/login-tokens/:token/consume (no auth required)\n */\nexport async function consumeLoginToken(loginToken: string): Promise<string> {\n  const response = await callCoreRpc<{ result: { jwtToken: string } }>({\n    method: 'openhuman.auth.consume_login_token',\n    params: { loginToken },\n  });\n  const jwtToken = response.result?.jwtToken;","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/app/src/services/api/authApi.ts#L22-L58","documentation":"The magic-link send request exceeded its client-side timeout: window.setTimeout aborted the fetch via AbortController, the AbortError was caught in the catch block, and it is rethrown as this friendly timeout message. The request never completed — the backend may or may not have sent the email.","triggerScenarios":"Slow or unreachable backend (fetch pending past timeoutMs); dev machine offline/VPN-blocked; backend cold start taking longer than the configured timeout. Any AbortError named signal from this controller maps here.","commonSituations":"Local backend still compiling when the login screen is used; network flakiness on mobile; an aggressive timeout constant after a latency regression; suspend/resume of the machine mid-request.","solutions":["Retry the send (the common case is transient) — but warn that a duplicate email may arrive if the first eventually succeeded","Verify network/backend reachability, then retry once the service responds to /health","Increase the timeout constant if the backend legitimately needs longer (cold starts)","Debounce the send button so impatience-driven duplicates don't stack timeouts"],"exampleFix":"// before\nawait sendMagicLink(email);\n\n// after\ntry {\n  await sendMagicLink(email);\n} catch (e) {\n  if (String(e.message).includes('timed out')) {\n    showNotice('The request timed out. Check your connection and try again.');\n    return;\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"const withTimeoutRetry = async (fn: () => Promise<void>, tries = 2) => {\n  for (let i = 0; i < tries; i++) {\n    try { return await fn(); }\n    catch (e) {\n      if (!String((e as Error).message).includes('timed out') || i === tries - 1) throw e;\n      await new Promise(r => setTimeout(r, 1000 * (i + 1)));\n    }\n  }\n};\nawait withTimeoutRetry(() => sendMagicLink(email));","preventionTips":["Disable the send button while a request is in flight to prevent stacking timeouts","Check backend reachability first when timeouts repeat","Raise the timeout constant if backend cold starts routinely exceed it"],"tags":["network","timeout","authentication"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}