{"record":{"id":"b6cae173c18c1844","repo":"lbjlaq/Antigravity-Manager","slug":"apikeyfun-errors-queryfailed","errorCode":null,"errorMessage":"apiKeyFun.errors.queryFailed","messagePattern":"apiKeyFun\\.errors\\.queryFailed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/pages/ApiKeyFun.tsx","lineNumber":244,"sourceCode":"                            baseUrl: endpoint // optionally update baseUrl\n                        };\n                        return updated;\n                    } else {\n                        // Automatically save new key\n                        return [{\n                            id: crypto.randomUUID(),\n                            key,\n                            name: maskKey(key),\n                            baseUrl: endpoint,\n                            createdAt: now,\n                            lastUsedAt: now,\n                            lastStatus: 'ok',\n                            lastRemaining: usageSummary?.remaining\n                        }, ...prev];\n                    }\n                });\n            } else {\n                throw new Error(t('apiKeyFun.errors.queryFailed', { defaultValue: '无法获取有效的额度数据或模型列表，请确认 API Key 是否有效，以及接口地址是否正确。' }));\n            }\n\n        } catch (error: any) {\n            console.error('Balance query failed', error);\n            setQueryError(error?.message || 'Query failed. Please verify network or key validity.');\n            setManagedKeys(prev => {\n                const existingIndex = prev.findIndex(item => item.key === key);\n                const now = Date.now();\n                if (existingIndex >= 0) {\n                    const updated = [...prev];\n                    updated[existingIndex] = {\n                        ...updated[existingIndex],\n                        lastStatus: 'bad',\n                        lastUsedAt: now,\n                        baseUrl: endpoint\n                    };\n                    return updated;\n                } else {","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/lbjlaq/Antigravity-Manager/blob/a2e3c454237d6d6ef423dfe20505b1ac62803c7c/src/pages/ApiKeyFun.tsx#L226-L262","documentation":"runQuery() in src/pages/ApiKeyFun.tsx:244 throws this aggregate error when, after probing the transit endpoint, no usageSummary could be built: the sub2api `/usage` attempt (line 151), and the One-API/New-API fallback `/dashboard/billing/subscription` + `/dashboard/billing/usage` (lines 180-191) all failed or returned unparsable bodies. Each probe failure is swallowed with console.log, so this message is the only user-visible symptom. Note the `/models` fetch does NOT trigger it — a key with valid billing but empty models still succeeds. In web mode, an extra cause applies: `query_transit_info` is not in COMMAND_MAPPING, so request() throws error [1] for every probe and all of them are caught, leaving usageSummary null.","triggerScenarios":"Querying a key against a base URL that is not a sub2api/One-API/New-API compatible relay (e.g. pointing at an OpenAI-compatible endpoint that lacks billing routes); invalid/expired API key so /usage and /dashboard/billing/* return 401; wrong or truncated base URL (missing scheme, wrong port, trailing /v1 mismatch); CORS/network failure in web mode; query_transit_info unmapped in Web mode (see error 1).","commonSituations":"User pastes the console URL instead of the API base URL, or includes /v1 when the relay expects the bare domain; the relay is a custom implementation without dashboard billing endpoints; the key has no quota endpoints enabled; running the web deployment where the transit proxy command was never mapped.","solutions":["Confirm the endpoint manually: curl -H \"Authorization: Bearer $KEY\" \"$ENDPOINT/usage\" and \"$ENDPOINT/dashboard/billing/subscription\" — if both 404/401, the URL or key is wrong.","In Web mode, add 'query_transit_info' to COMMAND_MAPPING in src/utils/request.ts (see error 1) — otherwise every probe silently fails and only this generic error appears.","Include the per-endpoint failure details in the thrown message (modelsError / last billing error) instead of only the generic i18n text, so users can see which probe failed and why.","Normalize the base URL before querying (strip trailing slashes, warn on missing scheme, optionally auto-retry with /v1 variant)."],"exampleFix":"// before (ApiKeyFun.tsx:243)\n} else {\n    throw new Error(t('apiKeyFun.errors.queryFailed', { defaultValue: '无法获取有效的额度数据或模型列表，请确认 API Key 是否有效，以及接口地址是否正确。' }));\n}\n\n// after: carry the concrete probe failure into the message\n} else {\n    const reason = modelsError || 'all billing endpoints (/usage, /dashboard/billing/*) failed';\n    throw new Error(t('apiKeyFun.errors.queryFailed', {\n        defaultValue: '无法获取有效的额度数据或模型列表，请确认 API Key 是否有效，以及接口地址是否正确。（{{err}}）',\n        err: reason\n    }));\n}","handlingStrategy":"try-catch","validationCode":"// Cheap pre-flight before the multi-endpoint probe\nfunction validateQueryInputs(key: string, endpoint: string): string | null {\n  if (!/^sk-[A-Za-z0-9_-]{8,}$/.test(key) && !/^[A-Za-z0-9_-]{16,}$/.test(key)) return 'key format looks invalid';\n  try { new URL(endpoint); } catch { return 'endpoint is not a valid absolute URL'; }\n  if (!/^https?:$/.test(new URL(endpoint).protocol)) return 'endpoint must be http(s)';\n  return null;\n}\n\nconst problem = validateQueryInputs(key, endpoint);\nif (problem) { setQueryError(problem); return; }","typeGuard":"const isBillingPayload = (v: unknown): v is { remaining?: number; balance?: number; quota?: unknown; usage?: unknown } =>\n  typeof v === 'object' && v !== null &&\n  ('remaining' in v || 'balance' in v || 'quota' in v || 'usage' in v);","tryCatchPattern":"// Aggregate probe results so the user sees WHICH endpoint failed\nconst failures: string[] = [];\ntry { /* /usage probe */ } catch (e: any) { failures.push(`/usage: ${e?.message ?? e}`); }\ntry { /* /dashboard/billing/* probe */ } catch (e: any) { failures.push(`/dashboard/billing: ${e?.message ?? e}`); }\nif (!usageSummary) {\n  throw new Error(`${t('apiKeyFun.errors.queryFailed')} (${failures.join('; ') || 'no billing endpoints available'})`);\n}","preventionTips":["In Web mode, confirm `query_transit_info` exists in COMMAND_MAPPING before shipping — an unmapped command makes every probe fail silently into this error.","Pre-validate the key format and that the endpoint parses as an absolute http(s) URL before querying.","Test new relays with curl against /models, /usage and /dashboard/billing/subscription first — this UI only understands those shapes.","Strip trailing slashes and warn on suspicious base URLs (no scheme, localhost in production, paths ending in unrelated segments) before probing."],"tags":["api-key","quota-query","one-api","new-api","network","web-mode"],"backgroundTag":"upstream-api-unreachable","analyzedSha":"a2e3c454237d6d6ef423dfe20505b1ac62803c7c","analyzedAt":"2026-08-16T19:44:46.389Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}