Skip to content

huma.WithContext() destroys original humago Context #784

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
akhayyat opened this issue Mar 30, 2025 · 3 comments · May be fixed by #829
Open

huma.WithContext() destroys original humago Context #784

akhayyat opened this issue Mar 30, 2025 · 3 comments · May be fixed by #829

Comments

@akhayyat
Copy link

I'm using humago.

I have a chain of middleware, and one of the later ones needs to use humago.Unwrap() to access the underlying http.Request to log some attributes that are not available in huma.Context (e.g. useragent).

One of the earlier middleware is injecting a key into the request context (context.Context), which naturally creates a new context. The new context is then reattached to the huma context using huma.WithContext().

However, after that point, humago.Unwrap(ctx) panics with the error: not a humago context.

If I move the panicking middleware up the chain so that it runs before the middleware that modifies the context, it works fine.

Here is a minimal example to reproduce the problem (TestMiddleware is the one that panics):

package main

import (
	"context"
	"net/http"

	"github.com/danielgtaylor/huma/v2"
	"github.com/danielgtaylor/huma/v2/adapters/humago"
)

func main() {
	router := http.NewServeMux()
	api := humago.New(router, huma.DefaultConfig("Campaigns", "1"))

	api.UseMiddleware(UpdateCtx, TestMiddleware)

	huma.Get(api, "/", handler)
	http.ListenAndServe(":8080", router)
}

type key struct{}

func UpdateCtx(ctx huma.Context, next func(huma.Context)) {
	// Inject key/value into context.
	ridCtx := context.WithValue(ctx.Context(), key{}, "value")
	ctx = huma.WithContext(ctx, ridCtx)
	next(ctx)
}

func TestMiddleware(ctx huma.Context, next func(huma.Context)) {
	req, _ := humago.Unwrap(ctx)
	println("Useragent:", req.UserAgent())

	next(ctx)
}

type Output struct {
	Body struct {
		Message string
	}
}

func handler(ctx context.Context, i *struct{}) (*Output, error) {
	output := Output{}
	output.Body.Message = "Hello"
	return &output, nil
}
@akhayyat
Copy link
Author

I also tried replacing:

	ridCtx := context.WithValue(ctx.Context(), key{}, "value")
	ctx = huma.WithContext(ctx, ridCtx)

with:

	ctx = huma.WithValue(ctx, key{}, "value")

but still got the same panic.

@akhayyat akhayyat changed the title huma.WithContext() destroys original huma.Context huma.WithContext() destroys original humago Context Apr 2, 2025
@akhayyat
Copy link
Author

akhayyat commented Apr 2, 2025

This seems to work:

func WithContext(ctx huma.Context, reqCtx context.Context) huma.Context {
	req, resp := humago.Unwrap(ctx)
	req = req.WithContext(reqCtx)
	ctx = humago.NewContext(ctx.Operation(), req, resp)
	return ctx
}

Usage:

func(ctx huma.Context) {
	...
	ctx = WithContext(ctx, context.WithValue(ctx.Context(), key{}, "value"))
}

It'd be great if huma.WithContext() and huma.WithValue() were fixed to preserve humago context.

@akhayyat
Copy link
Author

The workaround in the previous comment seems to break testing using the humatest package. Tests panic with not a humago context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant