{"record":{"id":"5b68a930b6aaccbd","repo":"gofiber/fiber","slug":"failed-to-read-response-w","errorCode":null,"errorMessage":"failed to read response: %w","messagePattern":"failed to read response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app.go","lineNumber":1492,"sourceCode":"\t}\n\n\t// Check for errors\n\tif err != nil && !errors.Is(err, fasthttp.ErrGetOnly) && !errors.Is(err, errTestConnClosed) {\n\t\treturn nil, err\n\t}\n\n\t// Read response(s)\n\tbuffer := bufio.NewReader(&conn.w)\n\n\tvar res *http.Response\n\tfor {\n\t\t// Convert raw http response to *http.Response\n\t\tres, err = httpReadResponse(buffer, req)\n\t\tif err != nil {\n\t\t\tif errors.Is(err, io.ErrUnexpectedEOF) {\n\t\t\t\treturn nil, ErrTestGotEmptyResponse\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"failed to read response: %w\", err)\n\t\t}\n\n\t\t// Break if this response is non-1xx or there are no more responses\n\t\tif res.StatusCode >= http.StatusOK || buffer.Buffered() == 0 {\n\t\t\tbreak\n\t\t}\n\n\t\t// Discard interim response body before reading the next one\n\t\tif res.Body != nil {\n\t\t\tif _, errCopy := io.Copy(io.Discard, res.Body); errCopy != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to discard interim response body: %w\", errCopy)\n\t\t\t}\n\t\t\tif errClose := res.Body.Close(); errClose != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to close interim response body: %w\", errClose)\n\t\t\t}\n\t\t}\n\t}\n","sourceCodeStart":1474,"sourceCodeEnd":1510,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/app.go#L1474-L1510","documentation":"After the handler runs, the TestClient parses the handler's response via httpReadResponse(buffer, req). If the response doesn't parse as valid HTTP (bad status line, malformed headers, chunked-encoding errors), the wrapped error is returned. Empty responses are mapped to ErrTestGotEmptyResponse separately.","triggerScenarios":"A handler under test writes a response that isn't well-formed HTTP: invalid status code text, illegal header bytes, broken chunked encoding, or hijacked connections.","commonSituations":"Custom serializers writing raw bytes; middleware that hijacks the connection; manually setting headers with control characters; version mismatches between handler and parser expectations.","solutions":["Use Fiber's standard response APIs (c.Status, c.Set, c.Write) so responses always serialize cleanly.","Avoid hijacking or writing raw bytes to the underlying fasthttp connection under test.","Inspect the wrapped error to localize the parse failure."],"exampleFix":"// before\napp.Get(\"/\", func(c fiber.Ctx) error {\n    c.Response().Header.Set(\"X-Bad\", \"a\\nb\")\n    return c.SendString(\"ok\")\n})\n\n// after\napp.Get(\"/\", func(c fiber.Ctx) error {\n    c.Set(\"X-Good\", \"a-b\")\n    return c.SendString(\"ok\")\n})","handlingStrategy":"validation","validationCode":"// Use fiber's response APIs so output is always well-formed HTTP\napp.Get(\"/\", func(c fiber.Ctx) error {\n    c.Set(\"X-Good\", \"a-b\")\n    return c.SendString(\"ok\")\n})","typeGuard":null,"tryCatchPattern":"resp, err := app.Test(req)\nif err != nil {\n    return fmt.Errorf(\"response parse failed in test client: %w\", err)\n}","preventionTips":["Use fiber's response APIs; avoid hijacking in handlers under test.","Never write control bytes into header values.","Run a smoke test against the started server to catch real-world response issues."],"tags":["testing","http","test-client","response"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}