{"record":{"id":"2684baa2dc04e098","repo":"gofiber/fiber","slug":"test-got-empty-response","errorCode":null,"errorMessage":"test: got empty response","messagePattern":"test: got empty response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app.go","lineNumber":1372,"sourceCode":"\n// Hooks returns the hook struct to register hooks.\nfunc (app *App) Hooks() *Hooks {\n\treturn app.hooks\n}\n\n// State returns the in-process state struct to store global data between handlers.\n// State is process-local and is not shared across prefork workers.\nfunc (app *App) State() *State {\n\treturn app.state\n}\n\n// SharedState returns storage-backed shared state.\n// SharedState is prefork-safe when Config.SharedStorage is configured.\nfunc (app *App) SharedState() *SharedState {\n\treturn app.sharedState\n}\n\nvar ErrTestGotEmptyResponse = errors.New(\"test: got empty response\")\n\n// TestConfig is a struct holding Test settings\ntype TestConfig struct {\n\t// Timeout defines the maximum duration a\n\t// test can run before timing out.\n\t// Default: time.Second\n\tTimeout time.Duration\n\n\t// FailOnTimeout specifies whether the test\n\t// should return a timeout error if the HTTP response\n\t// exceeds the Timeout duration.\n\t// Default: true\n\tFailOnTimeout bool\n}\n\n// Test is used for internal debugging by passing a *http.Request.\n// Config is optional and defaults to a 1s error on timeout,\n// 0 timeout will disable it completely.","sourceCodeStart":1354,"sourceCodeEnd":1390,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/app.go#L1354-L1390","documentation":"Returned by App.Test when reading the synthesized HTTP response hits io.ErrUnexpectedEOF — the in-process server closed the test connection before writing any bytes (app.go:1489-1491). Test() drives the handler through a pipe; if the handler never writes (e.g. calls Ctx.Drop()) the response stream is empty and EOF is translated to this sentinel so callers can distinguish 'no response' from other read failures.","triggerScenarios":"Calling app.Test(req) against a handler that invokes c.Drop() (test at app_test.go:2946-2959), a handler that panics before writing, or a handler path that returns without producing output. Also reachable when FailOnTimeout is false and the handler still produces nothing within the 1s grace window.","commonSituations":"Unit-testing handlers that intentionally drop the connection; testing error branches that bypass c.Send(); a misconfigured handler chain where middleware short-circuits with Drop(); TestConfig.Timeout=0 with FailOnTimeout=false amplifying the chance of an empty stream.","solutions":["If the empty response is unintended, fix the handler so it always writes a response (c.Send(), c.Status().SendString(), or returning an error that maps to a status) before returning.","If Drop() is intentional, treat ErrTestGotEmptyResponse as the expected outcome and assert it with errors.Is(err, fiber.ErrTestGotEmptyResponse) rather than require.NoError.","Set TestConfig.FailOnTimeout=true (the default) so a hung handler surfaces os.ErrDeadlineExceeded instead of silently producing an empty stream.","Set a non-zero TestConfig.Timeout to bound how long Test() waits before giving up."],"exampleFix":"// before\napp.Get(\"/\", func(c fiber.Ctx) error { return c.Drop() })\n_, err := app.Test(httptest.NewRequest(fiber.MethodGet, \"/\", nil))\nrequire.NoError(t, err) // fails: ErrTestGotEmptyResponse\n\n// after (handler writes a response)\napp.Get(\"/\", func(c fiber.Ctx) error { return c.SendString(\"ok\") })\n_, err := app.Test(httptest.NewRequest(fiber.MethodGet, \"/\", nil))\nrequire.NoError(t, err)","handlingStrategy":"try-catch","validationCode":"// Before calling app.Test, ensure the handler always writes a response\n// (audit the handler). For Drop()-by-design handlers, expect the sentinel:\nfunc runTest(t *testing.T, app *fiber.App, req *http.Request) {\n    _, err := app.Test(req)\n    if errors.Is(err, fiber.ErrTestGotEmptyResponse) {\n        // handler intentionally drops — treat as expected\n        return\n    }\n    if err != nil { t.Fatal(err) }\n}","typeGuard":null,"tryCatchPattern":"resp, err := app.Test(req)\nswitch {\ncase errors.Is(err, fiber.ErrTestGotEmptyResponse):\n    // handler wrote nothing — assert this is intended\ncase err != nil:\n    t.Fatalf(\"unexpected test error: %v\", err)\ndefault:\n    // use resp\n}","preventionTips":["Design handlers to always return either a response or a mapped error status — never silently drop.","Treat c.Drop() as an explicit decision and pair it with a test that asserts ErrTestGotEmptyResponse.","Keep TestConfig.FailOnTimeout at its default true so hung handlers surface DeadlineExceeded."],"tags":["testing","http","fiber","test-harness"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}