{"record":{"id":"64ebdb74b92e8b04","repo":"jlcodes99/cockpit-tools","slug":"message","errorCode":null,"errorMessage":"message","messagePattern":"message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pages/CodexApiServicePage.tsx","lineNumber":2137,"sourceCode":"    preferredAccountIds?: string[],\n    imageGenerationAccountPolicies?: Record<string, CodexLocalAccessImageGenerationPolicy>,\n  ) => {\n    setBusy(true);\n    setError(\"\");\n    setNotice(\"\");\n    try {\n      await saveMembers(\n        accountIds,\n        restrictFreeAccounts,\n        backupAccountIds,\n        preferredAccountIds,\n        imageGenerationAccountPolicies,\n      );\n      setNotice(t(\"codex.localAccess.saveSuccess\", \"API 服务集合已更新\"));\n    } catch (err) {\n      const message = String(err).replace(/^Error:\\s*/, \"\");\n      setError(message);\n      throw new Error(message);\n    } finally {\n      setBusy(false);\n    }\n  };\n\n  const handleRecoverAccounts = async (accountIds: string[]) => {\n    if (busy || accountIds.length === 0) return;\n    setBusy(true);\n    setError(\"\");\n    setNotice(\"\");\n    try {\n      const next =\n        await codexLocalAccessService.recoverCodexLocalAccessAccounts(\n          accountIds,\n        );\n      setState(next);\n      setNotice(\n        t(\"codex.localAccess.accountPoolHealth.recoverSuccess\", {","sourceCodeStart":2119,"sourceCodeEnd":2155,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/pages/CodexApiServicePage.tsx#L2119-L2155","documentation":"The Codex API-service save handler wraps its async work in try/catch; on failure it stringifies the error, strips the leading 'Error:' prefix, stores it via setError, and rethrows new Error(message). The bare message 'message' in a trace indicates an error was caught and rethrown here — the actual cause is the inner operation (e.g. error 82) whose text got flattened into a string.","triggerScenarios":"Any rejection inside the handleSaveLocalAccess try block (network failure, eligibility error, backend rejection) reaches the catch at CodexApiServicePage.tsx:2137 and is rethrown as new Error(String(err).replace(/^Error:\\s*/, '')).","commonSituations":"Saving the API-service set while an eligible-account error or request failure occurs; the rethrow propagates to an outer handler so the caller sees the re-wrapped message rather than the original stack.","solutions":["Inspect setError text / console for the original cause — the rethrown message is only a copy.","Fix the underlying error (e.g. no eligible accounts, network failure) rather than the rethrow site.","If the double-wrap complicates handling, log err before rethrowing or rethrow the original error object."],"exampleFix":"// before\n} catch (err) {\n  const message = String(err).replace(/^Error:\\s*/, \"\");\n  setError(message);\n  throw new Error(message);\n}\n// after\n} catch (err) {\n  const message = err instanceof Error ? err.message : String(err);\n  setError(message);\n  throw err; // preserve original stack/cause\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await saveLocalAccess();\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  setError(msg);\n  // do not rethrow a new Error; rethrow original to keep stack\n}","preventionTips":["Rethrow the original error object instead of new Error(String(err)) to preserve stack traces.","Use instanceof Error narrowing instead of String(err) to avoid 'Error: ' prefix surprises.","Log the original error before rewrapping so the root cause is diagnosable."],"tags":["error-handling","rethrow","codex"],"backgroundTag":"error-rethrow-wrapper","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}