{"record":{"id":"69e79ddad05189bc","repo":"bytedance/deer-flow","slug":"detailmessage-fallbackmessage-response-s","errorCode":null,"errorMessage":"detailMessage ?? `${fallbackMessage}: ${response.statusText}`","messagePattern":"detailMessage \\?\\? `(.+?): (.+?)`","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"frontend/src/core/memory/api.ts","lineNumber":75,"sourceCode":"      typeof detail === \"boolean\" ||\n      typeof detail === \"bigint\"\n    ) {\n      return String(detail);\n    }\n\n    if (typeof detail === \"symbol\") {\n      return detail.description ?? null;\n    }\n\n    return null;\n  }\n\n  if (!response.ok) {\n    const errorData = (await response.json().catch(() => ({}))) as {\n      detail?: unknown;\n    };\n    const detailMessage = formatErrorDetail(errorData.detail);\n    throw new Error(\n      detailMessage ?? `${fallbackMessage}: ${response.statusText}`,\n    );\n  }\n\n  return response.json() as Promise<UserMemory>;\n}\n\nexport async function loadMemory(): Promise<UserMemory> {\n  const response = await fetch(`${getBackendBaseURL()}/api/memory`);\n  return readMemoryResponse(response, \"Failed to fetch memory\");\n}\n\nexport async function clearMemory(): Promise<UserMemory> {\n  const response = await fetch(`${getBackendBaseURL()}/api/memory`, {\n    method: \"DELETE\",\n  });\n  return readMemoryResponse(response, \"Failed to clear memory\");\n}","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/frontend/src/core/memory/api.ts#L57-L93","documentation":"Thrown from readMemoryResponse when a /api/memory call returns non-2xx: it prefers the backend 'detail' message, falling back to '<fallbackMessage>: <statusText>'. The memory API persists per-user long-term memory, so failures typically reflect auth (401 after session expiry), disabled memory feature (404), or persistence backend errors (500).","triggerScenarios":"loadMemory()/save after the auth session expired (401 → JSON detail or empty body → fallback text); memory feature flag off in config.yaml (404); database migration not applied so the memory table is missing (500).","commonSituations":"Long-lived tab where the token expired; upgrading the backend and forgetting `make migrate-rev`/startup migrations; SQLite file permissions lost in a Docker volume.","solutions":["On 401, re-authenticate (re-run the auth flow) and retry the memory call","Check config.yaml enables the memory feature and the Gateway logged no startup warning","Apply pending backend migrations so /api/memory has its table","Read the thrown message — if it's the fallback text, inspect the raw response body server-side since no detail was returned"],"exampleFix":"// before\nconst mem = await loadMemory();\n\n// after\nconst mem = await loadMemory().catch(async (e) => {\n  if (String(e.message).startsWith('Failed to fetch memory')) {\n    await reauthenticate();\n    return loadMemory(); // one retry after fresh session\n  }\n  throw e;\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"export function isMemoryFetchError(e: unknown): e is Error {\n  return e instanceof Error && /^Failed to (fetch|save) memory/.test(e.message);\n}","tryCatchPattern":"try {\n  return await loadMemory();\n} catch (e) {\n  if (isMemoryFetchError(e) && await sessionExpired()) {\n    await reauthenticate();\n    return loadMemory(); // single retry\n  }\n  return EMPTY_USER_MEMORY; // memory is auxiliary\n}","preventionTips":["Treat memory load as best-effort; degrade gracefully","Run backend migrations after upgrades","Keep memory payloads small and validate shape before save"],"tags":["memory","auth","http","frontend"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}