{"record":{"id":"2f8bb85f36f5ab6a","repo":"glanceapp/glance","slug":"authentication-request-returned-status-s-with-mes","errorCode":null,"errorMessage":"authentication request returned status %s with message '%s'","messagePattern":"authentication request returned status (.+?) with message '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/glance/widget-dns-stats.go","lineNumber":650,"sourceCode":"\n\tbody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"reading authentication response: %v\", err)\n\t}\n\n\tvar jsonResponse struct {\n\t\tSession struct {\n\t\t\tSID     string `json:\"sid\"`\n\t\t\tMessage string `json:\"message\"`\n\t\t} `json:\"session\"`\n\t}\n\n\tif err := json.Unmarshal(body, &jsonResponse); err != nil {\n\t\treturn \"\", fmt.Errorf(\"parsing authentication response: %v\", err)\n\t}\n\n\tif response.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"authentication request returned status %s with message '%s'\",\n\t\t\tresponse.Status, jsonResponse.Session.Message,\n\t\t)\n\t}\n\n\tif jsonResponse.Session.SID == \"\" {\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"authentication response returned empty session ID, status code %d, message '%s'\",\n\t\t\tresponse.StatusCode, jsonResponse.Session.Message,\n\t\t)\n\t}\n\n\treturn jsonResponse.Session.SID, nil\n}\n\nfunc checkPiholeSessionIDIsValid(instanceURL string, client *http.Client, sessionID string) (bool, error) {\n\trequest, err := http.NewRequest(\"GET\", instanceURL+\"/api/auth\", nil)\n\tif err != nil {","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/glanceapp/glance/blob/91324e8de762702e97b0ac5c8e36271d644d8642/internal/glance/widget-dns-stats.go#L632-L668","documentation":"Returned by fetchPiholeSessionID when the auth response parsed as JSON but response.StatusCode != 200. The server explicitly rejected authentication; the message embeds the HTTP status line and the server-provided session.message (Pi-hole v6 reports reasons like 'password incorrect' there).","triggerScenarios":"Wrong password in the widget config (typically 401 Unauthorized); Pi-hole blocking due to too many failed attempts; FTL database locked or password not set server-side while one is sent.","commonSituations":"Password rotated in Pi-hole but not in glance config; password mangled by YAML (unquoted special chars like $, #, :); spaces copied along with the password.","solutions":["Read the embedded session.message — it states the server-side reason.","Re-enter the exact web UI password, quoted in YAML: password: \"p@$$word\".","Verify by logging into the Pi-hole web UI with the same credential.","If locked out from failed attempts, wait or clear the lockout on the Pi-hole side."],"exampleFix":"# before\npassword: mypa$$:word\n\n# after\npassword: \"mypa$$:word\"","handlingStrategy":"validation","validationCode":"// verify credentials out-of-band before configuring the widget\n// curl -X POST http://pihole/api/auth -H 'Content-Type: application/json' \\\n//   -d '{\"password\":\"<cfg password>\"}'  => expect 200 + session.sid","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"authentication request returned status\") {\n    // server rejected the credential — surface the embedded session.message\n    return fmt.Errorf(\"pihole rejected credentials: %v\", err)\n}","preventionTips":["Quote passwords in YAML: password: \"p@$$word\".","Update glance config immediately after rotating the Pi-hole password.","Watch for lockouts after repeated failures; wait or clear on the server."],"tags":["auth","pihole","password","dns-stats"],"backgroundTag":null,"analyzedSha":"91324e8de762702e97b0ac5c8e36271d644d8642","analyzedAt":"2026-08-15T14:12:54.279Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}