danielgtaylor / danielgtaylor/huma

Bug: Exploded array query parameter ignores its declared default

Open
#1,114 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
4.4k
Forks
285
Avg merge
40m
Merged PRs (30d)
1

Description

Hello 👋
I've found a thing that looks like a bug.

## Problem

An array query parameter declared with explode never receives its default when the parameter is absent from the request. The handler sees a nil slice instead.

The non-exploded form of the same declaration works correctly, and the generated OpenAPI document advertises the default in both cases. So the published spec and the runtime behaviour disagree.

Supplying the parameter explicitly works fine in both forms. Only the absent-parameter (default) path is broken, and only when explode is set.

If you want I already have a start of a fix ready locally and would be happy to push it.
Just wanted to ask if I was not mistaken and if it wasn't something expected before going deeper.

## Reproduction

My environment:
- huma v2.39.1
- Go 1.27.0 (macos)

```go
package repro

import (
"context"
"net/http"
"testing"

"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/humatest"
)

type Input struct {
Exploded []string `query:"exploded,explode" default:"a,b"`
NonExploded []string `query:"non-exploded" default:"a,b"`
}

type Output struct {
Body struct {
Exploded []string `json:"exploded"`
NonExploded []string `json:"non_exploded"`
}
}

func TestExplodeDefault(t *testing.T) {
_, api := humatest.New(t, huma.DefaultConfig("test", "1.0.0"))

huma.Register(api, huma.Operation{
OperationID: "demo",
Method: http.MethodGet,
Path: "/demo",
}, func(ctx context.Context, in *Input) (*Output, error) {
out := &Output{}
out.Body.Exploded = in.Exploded
out.Body.NonExploded = in.NonExploded
return out, nil
})

t.Log("no query params: ", api.Get("/demo").Body.String())
t.Log("params supplied: ", api.Get("/demo?exploded=a&exploded=b&non-exploded=a,b").Body.String())
}
```

Actual:
* no query params: {"exploded":null,"non_exploded":["a","b"]}
* params supplied: {"exploded":["a","b"],"non_exploded":["a","b"]}

Expected:
* no query params: {"exploded":["a","b"],"non_exploded":["a","b"]}
* params supplied: {"exploded":["a","b"],"non_exploded":["a","b"]}

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the TestExplodeDefault reproduction using humatest.New and huma.Register, then trace query decoding for the explode and default tags. Confirm the existing non-exploded behavior and explicit exploded values, then make the absent exploded parameter produce ["a","b"] as shown in the expected output.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.