{"record":{"id":"19dfcbfc337d9ae4","repo":"dani-garcia/vaultwarden","slug":"generation-failed-jsonresponse-statustext","errorCode":null,"errorMessage":"Generation failed: \" + jsonResponse.statusText","messagePattern":"Generation failed: \" \\+ jsonResponse\\.statusText","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/static/scripts/admin_diagnostics.js","lineNumber":127,"sourceCode":"    supportString += `* Server/NTP Time Check: ${chk(ntpTimeCheck)}\\n`;\n    supportString += `* Domain Configuration Check: ${chk(domainCheck)}\\n`;\n    supportString += `* HTTPS Check: ${chk(httpsCheck)}\\n`;\n    if (dj.enable_websocket) {\n        supportString += `* Websocket Check: ${chk(websocketCheck)}\\n`;\n    } else {\n        supportString += \"* Websocket Check: disabled\\n\";\n    }\n    supportString += `* HTTP Response Checks: ${chk(httpResponseCheck)}\\n`;\n    if (dj.invalid_feature_flags != \"\") {\n        supportString += \"* Invalid feature flags: true\\n\";\n    }\n\n    const jsonResponse = await fetch(`${BASE_URL}/admin/diagnostics/config`, {\n        \"headers\": { \"Accept\": \"application/json\" }\n    });\n    if (!jsonResponse.ok) {\n        alert(\"Generation failed: \" + jsonResponse.statusText);\n        throw new Error(jsonResponse);\n    }\n    const configJson = await jsonResponse.json();\n\n    // Start Config and Details section within a details block which is collapsed by default\n    supportString += \"\\n### Config & Details (Generated via diagnostics page)\\n\\n\";\n    supportString += \"<details><summary>Show Config & Details</summary>\\n\";\n\n    // Add overrides if they exists\n    if (dj.overrides != \"\") {\n        supportString += `\\n**Environment settings which are overridden:** ${dj.overrides}\\n`;\n    }\n\n    if (dj.invalid_feature_flags != \"\") {\n        supportString += `\\n**Invalid feature flags:** ${dj.invalid_feature_flags}\\n`;\n    }\n\n    // Add http response check messages if they exists\n    if (httpResponseCheck === false) {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/dani-garcia/vaultwarden/blob/0cefa4cca7c9f2a5579dd290f78193b543818c51/src/static/scripts/admin_diagnostics.js#L109-L145","documentation":"On the Vaultwarden admin diagnostics page, clicking Generate Support String builds a Markdown report and augments it with live config fetched from GET /admin/diagnostics/config. If that fetch returns a non-2xx status, the script alerts 'Generation failed: <statusText>' and throws new Error(jsonResponse) — note it passes a Response object, not a message, so the thrown error text is useless ('[object Response]' style). The most common non-OK status is 401 because the admin session cookie is missing or expired.","triggerScenarios":"Clicking Generate Support String after the admin session expired, after a server restart (sessions are invalidated), or after ADMIN_TOKEN changed; also a reverse proxy stripping the Cookie header, or a 500 from the config endpoint itself.","commonSituations":"Accessing the admin UI through a different host/port than BASE_URL; nginx/Traefik not forwarding cookies; CORS/credential issues when BASE_URL mismatches the page origin; instance restarted between login and report generation.","solutions":["Re-authenticate at /admin (re-enter the admin token) and retry generation","Make BASE_URL exactly match the URL used to open the admin UI so the session cookie scopes correctly","Verify the reverse proxy forwards the Cookie header without rewriting paths","Inspect server logs for errors on GET /admin/diagnostics/config when statusText suggests 5xx","Fix the script: throw new Error with the HTTP status instead of the Response object"],"exampleFix":"// before\nif (!jsonResponse.ok) {\n    alert(\"Generation failed: \" + jsonResponse.statusText);\n    throw new Error(jsonResponse);\n}\n// after\nif (!jsonResponse.ok) {\n    const detail = await jsonResponse.text().catch(() => \"\");\n    throw new Error(`Generation failed: HTTP ${jsonResponse.status} ${jsonResponse.statusText} ${detail.slice(0, 200)}`);\n}","handlingStrategy":"try-catch","validationCode":"// Run before generating the report: fail fast on a dead admin session\nasync function assertAdminSession(baseUrl) {\n    const probe = await fetch(`${baseUrl}/admin/diagnostics/config`, { credentials: 'same-origin', headers: { Accept: 'application/json' } });\n    if (probe.status === 401 || probe.status === 403) {\n        throw new Error(`Admin session invalid (HTTP ${probe.status}); log in again at ${baseUrl}/admin`);\n    }\n}","typeGuard":"const isJsonOk = (r) => r.ok && (r.headers.get('content-type') || '').includes('application/json');","tryCatchPattern":"try {\n    const jsonResponse = await fetch(`${BASE_URL}/admin/diagnostics/config`, {\n        headers: { Accept: 'application/json' },\n        credentials: 'same-origin'\n    });\n    if (!isJsonOk(jsonResponse)) {\n        throw new Error(`Config fetch failed: HTTP ${jsonResponse.status} ${jsonResponse.statusText}`);\n    }\n    const configJson = await jsonResponse.json();\n} catch (e) {\n    alert(`Generation failed: ${e.message}`);\n    throw e;\n}","preventionTips":["Keep BASE_URL identical to the address used to open the admin UI","Re-login after server restarts or ADMIN_TOKEN changes before using diagnostics","Ensure the reverse proxy forwards Cookie headers","Never throw non-Error objects; include status code and a body excerpt in the message"],"tags":["javascript","admin-ui","diagnostics","http","authentication"],"backgroundTag":null,"analyzedSha":"0cefa4cca7c9f2a5579dd290f78193b543818c51","analyzedAt":"2026-08-16T07:44:56.102Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}