v2 --v3.1: panic (nil pointer dereference) on query object fields of named types
Describe the bug
With OpenAPI 3.1 output (swag init --v3.1), swag panics with a nil pointer dereference when a struct used as an object query parameter has a field whose type is a named Go type rather than a builtin primitive.
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0xf8]
github.com/swaggo/swag/v2.(*OperationV3).ParseParamComment(...)
github.com/swaggo/swag/[email protected]/operationv3.go:399
github.com/swaggo/swag/v2.(*OperationV3).ParseComment(...)
github.com/swaggo/swag/[email protected]/operationv3.go:85
github.com/swaggo/swag/v2.(*Parser).ParseRouterAPIInfoV3(...)
github.com/swaggo/swag/[email protected]/parserv3.go:543The Swagger 2.0 code path and swag v1 handle the same input correctly, so this is specific to the OpenAPI 3 generator.
To Reproduce
main.go:
package main
// Include is a named string type with enum constants.
type Include string
const (
IncludeAuthor Include = "author"
IncludeComments Include = "comments"
)
// Query is bound from the query string.
type Query struct {
Includes []Include `json:"include"`
Limit int `json:"limit"`
}
// ListPosts lists posts.
//
// @Summary List posts
// @Param query query Query true "query"
// @Success 200 {string} string
// @Router /posts [get]
func ListPosts() {}
// @title Repro API
// @version 1.0
func main() {}$ swag init --v3.1 -g main.go -o ./docs
2026/07/28 22:07:45 Generating main.Query
2026/07/28 22:07:45 Generating main.Include
panic: runtime error: invalid memory address or nil pointer dereference
...Dropping --v3.1 (Swagger 2.0 output) succeeds and produces the expected spec, so the crash is limited to the v3 generator.
Affected field shapes
Every field whose type is a named type crashes; only builtin primitives survive. Two distinct panic sites are involved:
| Field | Result on v2.0.0-rc5 |
Line |
|---|---|---|
Includes []Include (named string with consts) |
panic | operationv3.go:399 |
Include Include (named string with consts) |
panic | operationv3.go:390 |
Items []Nested (named struct) |
panic | operationv3.go:399 |
Item Nested (named struct) |
panic | operationv3.go:390 |
Includes []string |
works | — |
Limit int |
works | — |
Root cause
ParseParamComment expands an object query parameter by iterating the properties of the struct schema:
for name, item := range schema.Spec.Properties {
prop := item.Spec
if len(*prop.Type) == 0 {
continue
}
itemParam := param
switch {
case (*prop.Type)[0] == ARRAY &&
prop.Items.Schema != nil &&
len(*prop.Items.Schema.Spec.Type) > 0 &&
IsSimplePrimitiveType((*prop.Items.Schema.Spec.Type)[0]):
...A property whose type is a named Go type is emitted as a $ref into #/components/schemas/..., i.e. a spec.RefOrSpec[spec.Schema] with Ref set and Spec == nil. The loop never resolves the reference:
prop := item.Specisnilfor a$refproperty, so*prop.Typedereferences nil — this is the scalar case.- For a slice of a named type the outer property does have a spec (
type: array), but itsItems.Schemais a$ref. Theprop.Items.Schema != nilguard passes whileprop.Items.Schema.Specis still nil, so*prop.Items.Schema.Spec.Typedereferences nil — this is the slice case.
The Swagger 2.0 implementation of the same loop (operation.go) does resolve references, via parser.getUnderlyingSchema, and additionally guards itemSchema for nil. The v3 port dropped both. This is the same class of bug as #2115 ("prevent panic when parsing custom string types with form tags in OpenAPI v3"), which fixed one other place where a $ref property's Spec was assumed non-nil.
Expected behavior
Match the Swagger 2.0 output: resolve the reference, expand named scalar and slice element types to their underlying type plus enum values, and skip fields whose underlying type is an object (swag already logs skip field [...] is not supported type for query for those).
Swagger 2.0 output for the reproducer above:
[
{
"type": "array",
"items": { "type": "string", "enum": ["author", "comments"] },
"collectionFormat": "csv",
"name": "include",
"in": "query"
}
]Your swag version
v2.0.0-rc5 (also reproduces on the current v2 branch, 8561606)
Your go version
go1.26.3 darwin/arm64 (also reproduces with go1.24.2)
Additional context
Happy to open a PR — I have a fix and a regression test ready. It adds a getUnderlyingSchemaV3 helper mirroring the v1 getUnderlyingSchema, and resolves the property (and array item) reference before inspecting its type.
Unrelated, but in the same function: operationv3.go:344 (rc5) has a leftover fmt.Println(schema.Spec.Type) that prints a raw type array to stdout whenever a @Param names an enum type. Let me know if you would like that removed in the same PR or a separate one.
Source: swaggo/swag