Skip to content

http server Bind errors bypass middleware chain (logging/tracing/recovery not executed) #3815

@robotmeta

Description

@robotmeta

Title

http server Bind errors bypass middleware chain (logging/tracing/recovery not executed)


Description

In the current go-kratos HTTP server implementation, request binding (Bind) happens before middleware execution. This leads to a critical issue:

If an error occurs during the binding phase (e.g., invalid request format, missing fields, or even a panic like nil pointer dereference), the middleware chain is never executed.

As a result:

  • Logging middleware is skipped
  • Tracing middleware is skipped
  • Metrics middleware is skipped
  • Recovery middleware cannot catch panics

This effectively breaks observability and stability guarantees.


Steps to Reproduce

  1. Create a HTTP handler with a request struct

  2. Send an invalid request (e.g., malformed JSON or missing required fields)

  3. Or trigger a panic inside binding (e.g., custom binder or pointer issue)

  4. Observe that:

    • No logs are generated
    • No tracing span is recorded
    • No metrics are emitted
    • Panic is not recovered

Expected Behavior

Even if binding fails or panics occur:

  • Middleware chain should still be executed
  • Logging / tracing / metrics should capture the failure
  • Recovery middleware should handle panics

Actual Behavior

  • Binding errors short-circuit the request lifecycle
  • Middleware chain is completely bypassed
  • Observability is lost
  • Panic may crash the process (depending on context)

Root Cause Analysis

From current behavior, it appears that:

Request → Bind → Handler → Middleware

Instead of the more robust design:

Request → Middleware → Bind → Handler

Because binding occurs before middleware, any failure at this stage prevents middleware from executing.


Suggested Solutions

Option 1: Move Bind into middleware stage (Recommended)

Make binding part of the middleware chain:

Request → Middleware (including Bind) → Handler

This ensures:

  • All errors are observable
  • Recovery middleware can catch panics
  • Consistent request lifecycle

Option 2: Wrap Bind with internal middleware-like handling

If moving Bind is not feasible:

  • Wrap binding logic with:

    • logging
    • tracing
    • panic recovery

But this duplicates middleware responsibilities and is less clean.


Option 3: Provide hook / interceptor before Bind

Expose a hook like:

BeforeBind(ctx, req)

So users can inject observability logic manually.


Option 4: Ensure recovery at the outermost layer

Guarantee that panic recovery exists outside Bind, even before middleware.


Additional Context

This issue has significant impact in production systems:

  • Silent failures (no logs, no traces)
  • Observability blind spots
  • Difficult debugging
  • Potential process crashes

Environment

  • go-kratos version: (please fill)
  • Go version: (please fill)
  • OS: (please fill)

Summary

The current execution order makes the system fragile and non-observable in case of binding errors. Adjusting the lifecycle so middleware wraps the entire request (including Bind) would greatly improve robustness and observability.


Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions