{"record":{"id":"5ce43b82e5d13fc1","repo":"jlcodes99/cockpit-tools","slug":"codexmodelproviders","errorCode":null,"errorMessage":"[CodexModelProviders] 额度类型探测失败","messagePattern":"\\[CodexModelProviders\\] 额度类型探测失败","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/components/codex/CodexModelProviderManager.tsx","lineNumber":2271,"sourceCode":"            apiKey: newApiKey,\n            integrationType: savedProvider.integrationType ?? null,\n          });\n          setProviderUsageMap((previous) => ({\n            ...previous,\n            [savedProvider.id]: { loading: false, summary: usageSummary },\n          }));\n          if (\n            (usageSummary.mode === \"sub2api\" ||\n              usageSummary.mode === \"new_api\") &&\n            usageSummary.mode !== savedProvider.integrationType\n          ) {\n            await saveCodexModelProviderDetectedIntegrationType(\n              savedProvider.id,\n              usageSummary.mode,\n            );\n          }\n        } catch (usageErr) {\n          console.warn(\"[CodexModelProviders] 额度类型探测失败\", usageErr);\n        }\n      }\n      if (savedProvider && currentEditingProvider) {\n        const linkedAccountIds = findCodexAccountsReferencingModelProvider(\n          currentEditingProvider,\n          accounts,\n        );\n        if (linkedAccountIds.length > 0) {\n          const presetId = resolveCodexApiProviderPresetId(savedProvider.baseUrl);\n          const isOpenAIOfficial = presetId === \"openai_official\";\n          const wireApi = resolveProviderWireApi(savedProvider);\n          const updatedAccountCount = await syncCodexApiKeyProviderAccounts({\n            accountIds: linkedAccountIds,\n            apiBaseUrl: savedProvider.baseUrl,\n            apiProviderMode: isOpenAIOfficial ? \"openai_builtin\" : \"custom\",\n            apiProviderId:\n              presetId === CODEX_API_PROVIDER_CUSTOM_ID\n                ? savedProvider.id","sourceCodeStart":2253,"sourceCodeEnd":2289,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/src/components/codex/CodexModelProviderManager.tsx#L2253-L2289","documentation":"In the Codex model provider manager controller, after saving a provider the app probes its usage/quota endpoint to detect the integration type (usageSummary.mode) and persists it via saveCodexModelProviderDetectedIntegrationType. If the probe throws, the warning is logged and the provider is still saved — only the detected quota type is not recorded, so the UI may show 'unknown' quota mode.","triggerScenarios":"Probing the provider's usage endpoint fails: unreachable custom base URL, invalid/expired API key, endpoint not implementing the expected usage API, TLS errors on self-signed certs, or a timeout on slow relays.","commonSituations":"Self-hosted/proxied Codex-compatible endpoints that don't expose the usage API, wrong API key pasted into the provider config, network blocking the endpoint, or a relay returning HTML instead of JSON.","solutions":["Read the logged usageErr for the concrete cause (401 → fix API key; timeout/ECONNREFUSED → fix URL/network).","Verify the provider's base URL and API key in the provider edit form and test connectivity.","If the endpoint intentionally has no usage API, ignore the warning and set the quota type manually in provider settings.","Re-save the provider once the endpoint is reachable so detection reruns."],"exampleFix":"// before\n} catch (usageErr) {\n  console.warn(\"[CodexModelProviders] 额度类型探测失败\", usageErr);\n}\n// after\n} catch (usageErr) {\n  console.warn(\"[CodexModelProviders] 额度类型探测失败\", usageErr);\n  await saveCodexModelProviderDetectedIntegrationType(savedProvider.id, 'unknown');\n}","handlingStrategy":"try-catch","validationCode":"// probe only when endpoint config looks complete\nif (!savedProvider.baseUrl || !savedProvider.apiKey) {\n  await saveCodexModelProviderDetectedIntegrationType(savedProvider.id, 'unknown');\n  return;\n}\n","typeGuard":"function isProbeableProvider(p: CodexModelProvider | undefined): p is CodexModelProvider & { baseUrl: string; apiKey: string } {\n  return !!p && typeof p.baseUrl === 'string' && p.baseUrl.startsWith('http') && typeof p.apiKey === 'string' && p.apiKey.length > 0;\n}\n","tryCatchPattern":"try {\n  const usageSummary = await probeUsageEndpoint(savedProvider);\n  await saveCodexModelProviderDetectedIntegrationType(savedProvider.id, usageSummary.mode);\n} catch (usageErr) {\n  console.warn(\"[CodexModelProviders] 额度类型探测失败\", usageErr);\n  // provider already saved; set fallback mode so UI isn't stuck on 'detecting'\n}\n","preventionTips":["Validate base URL and API key before saving a provider","Add a request timeout to the usage probe so slow relays fail fast","Treat probe failure as non-fatal — the provider save must succeed regardless","Provide a manual quota-type selector as a fallback when detection fails"],"tags":["network","codex","provider","probe","api-key"],"backgroundTag":"api-endpoint-unreachable","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"}