Nobody has started this yet — be first.
Business impact
The README advertises "every response carries X-Request-ID... so a single request's full retry/idempotency journey is traceable from one log grep." With the header silently dropped, a support engineer handed a customer-reported error has no correlation ID to grep server logs for -- they either have to reconstruct the request from timestamps and hope nothing else happened in that window, or ask the customer to reproduce the issue again. For an on-call engineer during an incident, that's the difference between finding the exact failing request in seconds versus minutes of log spelunking.
Problem
RequestIDMiddleware is supposed to set the X-Request-ID response header before the handler writes its response. It now calls the next handler first and sets the header afterward -- by which point the handler has already sent the status line (via w.WriteHeader, called inside writeJSON/writeError/writeStoredResponse), and a real HTTP server silently ignores header mutations made after that point.
Current behavior
Every response from this service is missing the X-Request-ID header entirely.
Expected behavior
Every response -- success or error, from every endpoint -- carries X-Request-ID, either echoing the caller-supplied value or a freshly generated one.
Steps to reproduce
go run ./cmd/server & curl -i localhost:8080/healthz | grep -i x-request-id
Note: httptest.NewRecorder() will NOT reproduce this -- see the note in test/README.md about why task08_test.go uses a real listener instead.
Why this matters
This is a real, easy-to-make Go HTTP gotcha: header mutations are only honored before the first Write/WriteHeader call on a ResponseWriter. Once the status line has gone out, further w.Header().Set(...) calls are silently no-ops on a real connection -- not an error, not a panic, just quietly ignored, which is exactly why this class of bug is easy to introduce during a refactor and easy to miss in testing that doesn't use a real transport.
Suggested approach
Look at the order of the three statements inside RequestIDMiddleware's handler closure: generating/reading the ID, calling next.ServeHTTP, and setting the response header. Compare that order to LoggingMiddleware right below it in the same file, which correctly reads response state (via statusWriter) only after next.ServeHTTP returns -- but critically never needs to write anything to the response after that point, which is the difference that matters here.
Acceptance criteria
Verification
go test ./test/ -run TestTask08 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b fix/request-id-droppedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/request-id-droppedSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:8080POST /v1/chargesTo run against Redis (the multi-replica-safe backend) with zero local setup:
docker compose up --build # app + redis, hot-reloading on save
Work the tickets in tasks/ (ordered easy → hard); each names one Go test in test/:
make test-race # go test -race -count=1 ./...
go test ./test/ -run TestTask01 -v # a single ticket
Level 1
Fix a bug
Read existing behaviour, correct it.