{"record":{"id":"a7ba0bb3d062c37a","repo":"milvus-io/milvus","slug":"http-error-resp-status","errorCode":null,"errorMessage":"HTTP error: ${resp.status}","messagePattern":"HTTP error: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/http/webui/telemetry.html","lineNumber":2391,"sourceCode":"            if (diffMs >= 60 * 60 * 1000) {\n                aggregate = true;\n            }\n\n            document.getElementById('historyModalContent').innerHTML = `\n                <div class=\"empty-state\" style=\"padding: 20px;\">\n                    <p>Loading historical metrics...</p>\n                </div>\n            `;\n\n            try {\n                const url = `${API_BASE}/_telemetry/clients/${encodeURIComponent(currentHistoryClientId)}/history?start_time=${encodeURIComponent(startTime)}&end_time=${encodeURIComponent(endTime)}&aggregate=${aggregate}`;\n                const resp = await fetch(url, {\n                    headers: { 'Authorization': `Basic ${authToken}` }\n                });\n\n                if (!resp.ok) {\n                    const errData = await resp.json();\n                    throw new Error(errData.error || `HTTP error: ${resp.status}`);\n                }\n\n                const data = await resp.json();\n\n                // The endpoint returns a command_id since it's async\n                // We need to wait for the command reply\n                if (data.status === 'pending') {\n                    document.getElementById('historyModalContent').innerHTML = `\n                        <div class=\"empty-state\" style=\"padding: 20px;\">\n                            <p>Command sent to client (ID: ${escapeHtml(data.command_id)})</p>\n                            <p style=\"margin-top: 10px; color: var(--gray-500);\">Results will be available in the client's next heartbeat.</p>\n                            <p style=\"margin-top: 10px; color: var(--gray-500);\">Waiting for client response...</p>\n                        </div>\n                    `;\n                    pollForCommandReply(data.command_id, currentHistoryClientId, 'history', aggregate);\n                    return;\n                }\n","sourceCodeStart":2373,"sourceCodeEnd":2409,"githubUrl":"https://github.com/milvus-io/milvus/blob/b43a76673a9fe5f01f158979731dc8fd542df81f/internal/http/webui/telemetry.html#L2373-L2409","documentation":"Thrown when fetching /_telemetry/clients/{id}/history for historical metrics fails: the code first tries to parse the error body and use its 'error' field, falling back to 'HTTP error: {status}'. Unlike other calls, this one sends 'Authorization: Basic ${authToken}' - if authToken already contains the 'Basic ' prefix (as stored at login), the header becomes 'Basic Basic ...' and the server returns 401, surfacing as this error.","triggerScenarios":"Opening the metrics history modal with a malformed Authorization header (double 'Basic ' prefix) producing 401; unknown/evicted client_id producing 404; invalid time range or aggregate parameter producing 400 with an error body.","commonSituations":"Auth header construction inconsistent with the rest of the page (other fetches send authToken verbatim); expired or evicted client; start_time > end_time or unsupported aggregate value.","solutions":["Check devtools Network tab for the exact status: if 401 on every history call but other tabs work, the 'Basic ' prefix duplication is the cause - send the header the same way as other calls.","For 400: verify start_time/end_time are valid epoch values with start < end and aggregate is a supported value.","For 404: refresh the client list and retry against a live client.","The server 'error' body field, when present, is already surfaced in the message - read it for the precise reason."],"exampleFix":"// before\nheaders: { 'Authorization': `Basic ${authToken}` }\n\n// after - match the header format used by every other telemetry call\nheaders: { 'Authorization': authToken }","handlingStrategy":"try-catch","validationCode":"// build the header exactly once, same as all other telemetry calls\nconst headers = { 'Authorization': authToken }; // authToken already includes the scheme\nconst url = `${API_BASE}/_telemetry/clients/${encodeURIComponent(id)}/history?start_time=${encodeURIComponent(startTime)}&end_time=${encodeURIComponent(endTime)}&aggregate=${encodeURIComponent(aggregate)}`;","typeGuard":null,"tryCatchPattern":"try {\n  const resp = await fetch(url, { headers });\n  if (resp.status === 401) { logout(); return; }\n  if (!resp.ok) {\n    const errData = await resp.json().catch(() => ({}));\n    throw new Error(errData.error || `HTTP error: ${resp.status}`);\n  }\n} catch (e) { renderHistoryError(e.message); }","preventionTips":["Use one shared header builder for every fetch so the Basic prefix is never duplicated.","Validate start_time < end_time and known aggregate values before building the URL.","Always attempt to read the JSON error body, but .catch() it - error responses are not always JSON."],"tags":["javascript","http","authentication","metrics","telemetry","webui"],"backgroundTag":null,"analyzedSha":"b43a76673a9fe5f01f158979731dc8fd542df81f","analyzedAt":"2026-08-15T10:29:28.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}