Skip to content

🐛 bug: answer healthcheck HEAD probes with the GET status - #4577

Merged
ReneWerner87 merged 2 commits into
mainfrom
fix/healthcheck-head-requests
Jul 30, 2026
Merged

🐛 bug: answer healthcheck HEAD probes with the GET status#4577
ReneWerner87 merged 2 commits into
mainfrom
fix/healthcheck-head-requests

Conversation

@ReneWerner87

Copy link
Copy Markdown
Member

Description

healthcheck.New() returned c.Next() for every method except GET, so a HEAD /livez ended up in the 404 handler while GET /livez answered 200. Since v3 auto-registers a HEAD twin for every GET route (DisableHeadAutoRegister), the HEAD request does reach the probe handler and the guard is what breaks it. RFC 9110 9.3.2 wants HEAD to answer with the GET status and no body, and fasthttp already drops the body on the wire, so the existing GET path can serve HEAD unchanged.

healthcheck was also the only outlier here: static, favicon and envvar all accept GET and HEAD.

Measured on main before the fix:

Registration GET HEAD
app.Get(healthcheck.LivenessEndpoint, healthcheck.New()) 200 404
app.All("/livez", healthcheck.New()) 200 404
app.Get("/livez", plainHandler) 200 200

Fixes #4574

Changes introduced

  • middleware/healthcheck: let HEAD through the same probe path as GET; other methods still fall through to the next handler.
  • Test: Test_HealthCheck_Head asserts 200 for a healthy probe, 503 for an unhealthy one, and an empty body in both cases.
  • Documentation Update: docs/middleware/healthcheck.md no longer claims the middleware responds only to GET.

Type of change

  • Code consistency (non-breaking change which improves code reliability and robustness)
  • Documentation update (changes to documentation)

The handler bailed out to c.Next() for anything but GET, so the HEAD route
that v3 auto-registers for every GET route ran the probe handler and then
fell through to 404. Every other GET-oriented middleware (static, favicon,
envvar) already accepts HEAD; fasthttp drops the body on the wire, so the
GET path can serve it unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b74f704f-6cfb-452f-9f97-f1f0e20481f9

📥 Commits

Reviewing files that changed from the base of the PR and between f1df1ca and 9aefddd.

📒 Files selected for processing (1)
  • middleware/healthcheck/healthcheck_test.go

Walkthrough

The healthcheck middleware now handles both GET and HEAD requests. HEAD responses match GET status codes and selected headers while omitting the response body. Tests cover method fallthrough, and documentation describes the updated behavior.

Changes

Healthcheck HEAD support

Layer / File(s) Summary
HEAD probe handling and validation
middleware/healthcheck/healthcheck.go, middleware/healthcheck/healthcheck_test.go, docs/middleware/healthcheck.md
The middleware allows HEAD requests through health probes, validates matching status and headers with empty bodies, verifies POST fallthrough, and documents GET/HEAD behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • gofiber/fiber#4576: Makes the same healthcheck HEAD-handling change and adds equivalent tests.

Suggested labels: 📒 Documentation

Suggested reviewers: sixcolors, efectn, gaby

Poem

A rabbit checks the probe at dawn,
HEAD hops in, the bytes are gone.
Status and headers match the trail,
POST falls through when probes fail.
Docs bloom softly by the tree.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main fix: HEAD healthcheck probes now use the GET status.
Description check ✅ Passed The description follows the template, includes the issue reference, change summary, type of change, and documentation update.
Linked Issues check ✅ Passed The change makes HEAD follow the same probe path as GET, preserves empty bodies, and adds tests for status/header parity and fallthrough.
Out of Scope Changes check ✅ Passed The PR stays focused on healthcheck HEAD handling, tests, and docs; no unrelated changes are present.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/healthcheck-head-requests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.28%. Comparing base (1104ec3) to head (9aefddd).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4577      +/-   ##
==========================================
- Coverage   93.29%   93.28%   -0.01%     
==========================================
  Files         140      140              
  Lines       14858    14858              
==========================================
- Hits        13862    13861       -1     
- Misses        620      622       +2     
+ Partials      376      375       -1     
Flag Coverage Δ
unittests 93.28% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes the healthcheck middleware so HEAD requests follow the same probe path as GET, returning the same status codes (200/503) while producing an empty response body, aligning behavior with RFC 9110 §9.3.2 and Fiber v3’s auto-registered HEAD routes.

Changes:

  • Allow HEAD requests through the healthcheck probe handler (previously only GET was handled; HEAD fell through to c.Next()).
  • Add a regression test covering HEAD responses for healthy/unhealthy probes and asserting an empty body.
  • Update healthcheck documentation to reflect GET + HEAD behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
middleware/healthcheck/healthcheck.go Extends the method guard to handle HEAD the same as GET.
middleware/healthcheck/healthcheck_test.go Adds Test_HealthCheck_Head to validate status mirroring and empty body semantics.
docs/middleware/healthcheck.md Updates docs to state the middleware responds to GET and HEAD.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@middleware/healthcheck/healthcheck_test.go`:
- Around line 166-193: Extend Test_HealthCheck_Head to issue a GET request for
each endpoint and use it as the reference response. Assert that the HEAD
response matches the corresponding GET status and headers while retaining the
existing empty-body assertion; keep the liveness and readiness cases unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9eb43aab-a072-44b6-ba4d-90fc9b674f1b

📥 Commits

Reviewing files that changed from the base of the PR and between 1104ec3 and f1df1ca.

📒 Files selected for processing (3)
  • docs/middleware/healthcheck.md
  • middleware/healthcheck/healthcheck.go
  • middleware/healthcheck/healthcheck_test.go

Comment thread middleware/healthcheck/healthcheck_test.go
Compare Content-Type and Content-Length against a real GET response instead
of only checking the HEAD status. Date stays out of the comparison, fasthttp
refreshes its cached value once per second, so a full header-map compare
across two requests would flake.

The POST case also restores coverage for the c.Next() fallthrough: with a
GET-only registration the router answers 405 before the middleware runs, so
codecov saw the changed line as unhit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

This comment was marked as outdated.

@ReneWerner87
ReneWerner87 merged commit 8638fb8 into main Jul 30, 2026
29 of 30 checks passed
@ReneWerner87
ReneWerner87 deleted the fix/healthcheck-head-requests branch July 30, 2026 13:28
@github-project-automation github-project-automation Bot moved this to Done in v3 Jul 30, 2026
ReneWerner87 pushed a commit to gofiber/.github that referenced this pull request Jul 30, 2026
…not share a CPU

A regression gate is only meaningful when both sides saw the same hardware.
Two cases break that and both went through silently.

A sharded run can span several CPU models. The cache key carries the merged
model string, so such a run lands in its own baseline lineage, and that lineage
is only refreshed when a default branch run happens to be mixed the same way.
Meanwhile the restore-key is an unbounded prefix fallback, so it takes the
newest entry in that lineage no matter how old.

Seen on gofiber/fiber#4577: one of six shards ran on Neoverse-N1 while the rest
ran on Ampere-1a, and the comparison fell back to a baseline 12 commits behind
the PR base. It reported 11 regressions of 1.50x to 2.72x. Three were the
Neoverse shard measured against Ampere numbers, Neoverse-N1 being 1.5x to 2.3x
slower here. The other eight were byte for byte what the default branch measures
today and only looked worse because the baseline was old.

Skip the comparison when the run spanned more than one model, and when a
pages-cpu-model pin is configured and the run did not meet it. A skipped
comparison is a visible warning; a comparison across machines is a wrong number
presented as a fact.

Also stop seeding the cache from such a run, otherwise the default branch keeps
creating exactly the stale lineages this guard exists to avoid.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

bug(healthcheck): HEAD requests return 404 instead of matching GET status

3 participants