huma icon indicating copy to clipboard operation
huma copied to clipboard

No way to get a 406 code back?

Open jh125486 opened this issue 5 months ago • 2 comments
trafficstars

I'm currently migrating an app to Huma, and some of my tests intentionally send invalid Accept headers expecting a 406 Not Acceptable.

Weirdly enough, it always returns back JSON.

I think I've narrowed it down to this: https://github.com/danielgtaylor/huma/blob/main/api.go#L297-L306

func (a *api) Negotiate(accept string) (string, error) {
	ct := negotiation.SelectQValueFast(accept, a.formatKeys)
	if ct == "" && a.formatKeys != nil {
		ct = a.formatKeys[0]
	}
	if _, ok := a.formats[ct]; !ok {
		return ct, fmt.Errorf("unknown content type: %s", ct)
	}
	return ct, nil
}

SelectQValueFast() returns "" (from // Skip formats we don't support.), so it picks the first format from formatKeys.

So there's no way to ever return a 406 from what I can tell. I'm not sure if that's the correct intention?

jh125486 avatar Jun 18 '25 20:06 jh125486

@jh125486 I think the intent was to just always fall back to JSON as that's the most common web API format and it helps when things may not be set up exactly right and custom ...+json formats get used. It's certainly not perfect and I'm willing to revisit this, but I'm a bit afraid of breaking people too. What do people prefer for this?

danielgtaylor avatar Jun 19 '25 00:06 danielgtaylor

To avoid a breaking change, I can add a field to Config... something like NoFormatFallback bool ? Obviously we can wordsmith the naming.

If set to true, then it would short-circuit after an empty return from SelectQValueFast() with an error, skipping the ct = a.formatKeys[0].

jh125486 avatar Jun 19 '25 19:06 jh125486