{"record":{"id":"f4759c19b75a5f8c","repo":"VictoriaMetrics/VictoriaMetrics","slug":"unexpected-status-code-for-q-got-d-want-d-re-f4759c","errorCode":null,"errorMessage":"unexpected status code for %q; got %d; want %d; response body: %q","messagePattern":"unexpected status code for %q; got (.+?); want (.+?); response body: %q","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/promscrape/discovery/openstack/api.go","lineNumber":185,"sourceCode":"\t\treturn nil, fmt.Errorf(\"cannot get computeEndpoint, account doesn't have enough permissions, \"+\n\t\t\t\"availability: %s, region: %s; error: %w\", cfg.availability, cfg.region, err)\n\t}\n\treturn &apiCredentials{\n\t\ttoken:      at,\n\t\texpiration: ar.Token.ExpiresAt,\n\t\tcomputeURL: computeURL,\n\t}, nil\n}\n\n// readResponseBody reads body from http.Response.\nfunc readResponseBody(resp *http.Response, apiURL string) ([]byte, error) {\n\tdata, err := io.ReadAll(resp.Body)\n\t_ = resp.Body.Close()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot read response from %q: %w\", apiURL, err)\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"unexpected status code for %q; got %d; want %d; response body: %q\",\n\t\t\tapiURL, resp.StatusCode, http.StatusOK, data)\n\t}\n\treturn data, nil\n}\n\n// getAPIResponse calls openstack apiURL and returns response body.\nfunc getAPIResponse(apiURL string, cfg *apiConfig) ([]byte, error) {\n\tcreds, err := cfg.getFreshAPICredentials()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq, err := http.NewRequest(http.MethodGet, apiURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot create new request for openstack api url %s: %w\", apiURL, err)\n\t}\n\treq.Header.Set(\"X-Auth-Token\", creds.token)\n\tresp, err := cfg.client.Do(req)\n\tif err != nil {","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/VictoriaMetrics/VictoriaMetrics/blob/5079fb58f1e8e62113f90c945ad71586c797d770/lib/promscrape/discovery/openstack/api.go#L167-L203","documentation":"readResponseBody expects HTTP 200 from Nova API endpoints. Any other status code produces this error including the actual code and the response body, which usually contains Nova's JSON error explanation (e.g. 401 unauthorized, 403 forbidden, 404 not found).","triggerScenarios":"The GET to the hypervisors or servers detail URL returns a non-200 code — expired/invalid X-Auth-Token (401), insufficient role (403), wrong compute URL (404), or Nova 5xx.","commonSituations":"Token expired between auth and query; user lacks 'member'/'reader' role required by newer Nova API policy (401/403); SDConfig role too low for hypervisor visibility (hypervisor listing requires admin-ish roles); microversion/policy changes after a Nova upgrade.","solutions":["Read the response body in the error — Nova usually says exactly why (auth required, forbidden, not found)","If 401: check that the token isn't expiring quickly; verify credentials and clocks (token expiry is UTC)","If 403: grant the discovery user the required role (e.g. reader or member) on the project; hypervisor endpoints need elevated roles","If 404: verify the compute endpoint URL/region and Nova API path still exists (API version changes)","Check Nova API logs and recent policy.json/upgrades for breaking changes"],"exampleFix":"// before (role insufficient for hypervisor listing)\nrole: member\n// after (grant elevated read role for hypervisors)\nrole: admin  # or 'reader' on Nova with newer default policies","handlingStrategy":"fallback","validationCode":"# reproduce the exact API call before enabling discovery\nCOMPUTE_URL=$(openstack endpoint list | awk '/compute.*public/{print $10}')\ncurl -sS -H \"X-Auth-Token: $TOKEN\" \"$COMPUTE_URL/servers/detail?all_tenants=true\" -w '\\n%{http_code}\\n'\n# must be 200; body explains 401/403/404 causes","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unexpected status code\") {\n    switch {\n    case strings.Contains(err.Error(), \"got 401\"), strings.Contains(err.Error(), \"got 403\"):\n        log.Errorln(\"nova rejected token/role; fix credentials or grant reader role:\", err)\n    default:\n        log.Errorln(\"nova api error; inspect body in error:\", err)\n    }\n    return\n}","preventionTips":["Read the response body included in the error — Nova explains the failure","Grant the discovery user the role Nova policy requires (reader/member/admin)","Refresh credentials appropriately if tokens expire mid-scrape","Track Nova policy/default-role changes when upgrading OpenStack"],"tags":["http-status","openstack","nova","auth"],"backgroundTag":"api-unexpected-status-code","analyzedSha":"5079fb58f1e8e62113f90c945ad71586c797d770","analyzedAt":"2026-09-03T18:10:26.153Z","contentChangedAt":"2026-09-03T18:10:26.153Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}