{"record":{"id":"04cd610c0a071836","repo":"AlexxIT/go2rtc","slug":"hap-wrong-http-status","errorCode":null,"errorMessage":"hap: wrong http status: ","messagePattern":"hap: wrong http status: ","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/hap/client_http.go","lineNumber":44,"sourceCode":"\tif c.res != nil {\n\t\treturn <-c.res, c.err\n\t}\n\treturn http.ReadResponse(c.reader, req)\n}\n\nfunc (c *Client) Request(method, path, contentType string, body io.Reader) (*http.Response, error) {\n\treq, err := http.NewRequest(method, \"http://\"+c.DeviceAddress+path, body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif contentType != \"\" {\n\t\treq.Header.Set(\"Content-Type\", contentType)\n\t}\n\n\tres, err := c.Do(req)\n\tif err == nil && res.StatusCode >= http.StatusBadRequest {\n\t\terr = errors.New(\"hap: wrong http status: \" + res.Status)\n\t}\n\n\treturn res, err\n}\n\nfunc (c *Client) Get(path string) (*http.Response, error) {\n\treturn c.Request(\"GET\", path, \"\", nil)\n}\n\nfunc (c *Client) Post(path, contentType string, body io.Reader) (*http.Response, error) {\n\treturn c.Request(\"POST\", path, contentType, body)\n}\n\nfunc (c *Client) Put(path, contentType string, body io.Reader) (*http.Response, error) {\n\treturn c.Request(\"PUT\", path, contentType, body)\n}\n\nconst ProtoEvent = \"EVENT/1.0\"","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/hap/client_http.go#L26-L62","documentation":"Client.Request is the shared HTTP layer for Get/Post/Put against the HAP accessory. When the response status is >= 400 it converts it into this error, appending res.Status (e.g. \"hap: wrong http status: 401 Unauthorized\"). The accessory rejected the request at the HTTP level.","triggerScenarios":"Calling Get/Post/Put with an expired or missing HAP session (401); sending a malformed characteristics write (400); requesting a path the accessory does not expose (404); hitting the accessory while it is busy (503).","commonSituations":"Session keys stale after the accessory rebooted; writing characteristics with wrong format/values; probing endpoints removed by a firmware update; too many concurrent connections to a constrained accessory.","solutions":["Read the status embedded in the error: 401/404 on session endpoints usually means re-establish the HAP session (Dial) or re-pair.","For 400, validate the characteristic format/value and the query string before retrying.","For 5xx, retry with backoff — accessories are embedded devices and can be temporarily busy.","Verify the request path and Content-Type match what the accessory expects (PathAccessories, PathCharacteristics, PathPairings)."],"exampleFix":"// before: treating every failure the same\nres, err := client.Get(hap.PathCharacteristics + \"?id=\" + q)\n// after: branch on the HTTP status embedded in the error\nres, err := client.Get(hap.PathCharacteristics + \"?id=\" + q)\nif err != nil {\n    if strings.Contains(err.Error(), \"401\") {\n        // session lost: re-establish then retry once\n        if e := client.Dial(); e == nil {\n            res, err = client.Get(hap.PathCharacteristics + \"?id=\" + q)\n        }\n    }\n    if err != nil { return err }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"res, err := client.Get(path)\nif err != nil {\n    var status int\n    if strings.HasPrefix(err.Error(), \"hap: wrong http status: 4\") {\n        status = httpStatusFromErr(err) // 401 -> re-Dial, 404 -> bad path\n    }\n    switch {\n    case status == 401:\n        if e := client.Dial(); e == nil { res, err = client.Get(path) }\n    case strings.HasPrefix(err.Error(), \"hap: wrong http status: 5\"):\n        time.Sleep(time.Second); res, err = client.Get(path)\n    }\n    if err != nil { return err }\n}","preventionTips":["Re-establish the HAP session (Dial) whenever you start seeing 4xx on previously working calls.","Validate characteristic IDs, formats, and query strings before writes to avoid 400s.","Back off on 5xx — HAP accessories are constrained embedded devices.","Log res.Status values to spot firmware updates that changed endpoint availability."],"tags":["hap","http","http-status","homekit"],"backgroundTag":"http-error-status","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}