{"record":{"id":"ef503cb068db5fc8","repo":"BigPizzaV3/CodexPlusPlus","slug":"codex-api-errors-join","errorCode":null,"errorMessage":"Codex 状态 API 不可用 (${errors.join(\"; \")})","messagePattern":"Codex 状态 API 不可用 \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"assets/inject/renderer-inject.js","lineNumber":6469,"sourceCode":"      return typeof module?.qut === \"function\" ? module.qut : null;\n    }\n    return null;\n  }\n\n  async function codexStateApi() {\n    codexStateApiPromise = codexStateApiPromise || (async () => {\n      const errors = [];\n      for (const assetPrefix of [\"vscode-api-\", \"app-initial-\"]) {\n        try {\n          const api = await loadCodexAppModule(assetPrefix);\n          const call = codexStateApiFromModule(api, assetPrefix);\n          if (typeof call === \"function\") return call;\n          errors.push(`${assetPrefix}: state export unavailable`);\n        } catch (error) {\n          errors.push(`${assetPrefix}: ${error?.message || String(error)}`);\n        }\n      }\n      throw new Error(`Codex 状态 API 不可用 (${errors.join(\"; \")})`);\n    })();\n    return await codexStateApiPromise;\n  }\n\n  async function codexStateCall(method, params) {\n    const call = await codexStateApi();\n    return await call(method, params);\n  }\n\n  async function getCodexGlobalState(key) {\n    const result = await codexStateCall(\"get-global-state\", { params: { key } });\n    return result && Object.prototype.hasOwnProperty.call(result, \"value\") ? result.value : result;\n  }\n\n  async function setCodexGlobalState(key, value) {\n    return await codexStateCall(\"set-global-state\", { params: { key, value } });\n  }\n","sourceCodeStart":6451,"sourceCodeEnd":6487,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/assets/inject/renderer-inject.js#L6451-L6487","documentation":"codexStateApi() memoizes a one-shot async probe that tries to obtain Codex's state/call export (the bridge for invoking app-server JSON-RPC methods like codexStateCall) across all known asset prefixes. If every probe fails — the state export is missing or throws — the aggregated per-prefix errors are joined into this thrown message, and the memoized promise rejects for all subsequent callers.","triggerScenarios":"Any codexStateCall(method, params) invocation when the probe found no callable state export: Codex updated and renamed the state module, the chunk hosting it isn't loaded yet, or the inject script's assetPrefix list is outdated. Once rejected, the memoized promise keeps failing.","commonSituations":"Codex renderer upgrade changed internal exports; inject script version mismatch; probe raced ahead of lazy chunk loading; bundler hash changes invalidated the module lookup paths.","solutions":["Update the inject script's assetPrefix list and export names to match the installed Codex build (inspect the joined per-prefix error messages).","Reset the memoized promise and retry probing after a delay so lazy chunks can load.","Align Codex and inject script versions (pin or update one to match the other).","Add a fallback bridge (e.g. postMessage to a background/agent layer) if the in-page export is gone."],"exampleFix":"// before\nconst call = await codexStateApi();\n// after\nlet call;\ntry { call = await codexStateApi(); }\ncatch (e) {\n  resetCodexStateApi(); // clear memoized rejected promise\n  await new Promise(r => setTimeout(r, 1500));\n  call = await codexStateApi();\n}","handlingStrategy":"retry","validationCode":"let available = true; try { await codexStateApi(); } catch { available = false; } if (!available) { /* disable state-dependent UI and prompt update */ }","typeGuard":"function isStateApi(call) { return typeof call === \"function\"; }","tryCatchPattern":"try { const call = await codexStateApi(); } catch (e) { resetCodexStateApi(); await sleep(1500); return codexStateApi().catch(() => notifyUser(\"Codex 状态接口不可用\")); }","preventionTips":["Clear the memoized rejected promise before retrying, or it will fail forever.","Update assetPrefix/export names whenever Codex internals change.","Probe once at startup and degrade UI features gracefully instead of failing per-call."],"tags":["injection","codex","api","version-mismatch"],"backgroundTag":"module-init-failed","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}