You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
line 45: cannot construct !!str `#/compo...` into parser.PathItem
Reproduces on tests/schema/pass/path_item_servers_parameters.yaml from OAI/OpenAPI-Specification@v3.2-dev. It is the last remaining positive-fixture failure not owned by #434.
Why this one is structurally awkward
OAS 3.2 has nine-or-reference unions: parameter, request-body, media-type, response, callbacks, example, link, header, security-scheme.
Eight are objects with fixed field names, so oastools models each as a struct with a Ref string field — $ref cannot collide with name, schema, description. Link, Response and Parameter all do exactly this.
The Callback Object is the outlier: an open map keyed by user-authored runtime expressions, so $ref shares a key namespace with them. The spec discriminates on key presence (schema.yaml:737):
A named map type has methods but no fields, so there is nowhere to put Ref. The parser hands $ref to the map as if it were a runtime expression and fails building a PathItem from the string.
Options examined
Option
Additive?
Verdict
type Callback struct { Ref string; Expressions map[string]*PathItem }
✗
Correct model. Breaks walker.CallbackHandler (walker/walker.go:117) — a public signature users implement — plus validator/oas32_gate.go:321, joiner and fixer. Needs a major version
Reserved "$ref" key inside the existing map
✓ compiles
Rejected. Leaks a key that is not a runtime expression into every consumer that ranges the map, third-party handlers included. Silent corruption is worse than a parse error
Union at the container: map[string]*CallbackOrReference
✗
Same breakage relocated; the field types on Operation and Components are public
Parallel field
✓
Chosen — see below
Resolve/inline the $ref at parse time
✓
Rejected — lossy, and references are preserved verbatim for lossless round-trips
Approach: a parallel field
Add CallbackRefs map[string]*Reference beside the existing Callbacks map[string]*Callback on both Operation (parser/paths.go:46) and Components (parser/oas3.go:41), tagged yaml:"-" json:"-", and merge both back into a single callbacks: object when serializing. parser.Reference already exists (parser/common.go:88) with Ref/Summary/Description, so the value type is off the shelf.
Buys: parses, round-trips losslessly, no public signature change.
Costs: one specification field represented by two Go fields — an invariant the parser must police, since a key must not appear in both. Consumers reading only Callbacks will miss referenced ones; today they cannot parse the document at all, so it is strictly an improvement.
Acceptance
pass/path_item_servers_parameters.yaml parses and validates clean; the reference round-trips verbatim in both YAML and JSON.
walker gains an additive handler if references should be walkable; existing CallbackHandler behaviour is unchanged.
Context
Callbacks are rare in practice — none of the ten real-world specs in the corpus use them, and only two fixtures in the OAI 3.2 suite mention them. The cost of the gap is not frequency but blast radius: a document that merely contains one referenced callback fails to parse entirely, rather than degrading.
Epic A — Correct the measured conformance defects · Size M · Release v1.60.0 · Blocked by: nothing
The second half of #447. The boolean-schema half landed in #450; this is the part that needed a different approach.
The defect
A Callback Object may be a Reference Object. oastools cannot decode that form, and rejects the entire document:
Reproduces on
tests/schema/pass/path_item_servers_parameters.yamlfromOAI/OpenAPI-Specification@v3.2-dev. It is the last remaining positive-fixture failure not owned by #434.Why this one is structurally awkward
OAS 3.2 has nine
-or-referenceunions:parameter,request-body,media-type,response,callbacks,example,link,header,security-scheme.Eight are objects with fixed field names, so oastools models each as a struct with a
Ref stringfield —$refcannot collide withname,schema,description.Link,ResponseandParameterall do exactly this.The Callback Object is the outlier: an open map keyed by user-authored runtime expressions, so
$refshares a key namespace with them. The spec discriminates on key presence (schema.yaml:737):In Go:
A named map type has methods but no fields, so there is nowhere to put
Ref. The parser hands$refto the map as if it were a runtime expression and fails building aPathItemfrom the string.Options examined
type Callback struct { Ref string; Expressions map[string]*PathItem }walker.CallbackHandler(walker/walker.go:117) — a public signature users implement — plusvalidator/oas32_gate.go:321, joiner and fixer. Needs a major version"$ref"key inside the existing mapmap[string]*CallbackOrReferenceOperationandComponentsare public$refat parse timeApproach: a parallel field
Add
CallbackRefs map[string]*Referencebeside the existingCallbacks map[string]*Callbackon bothOperation(parser/paths.go:46) andComponents(parser/oas3.go:41), taggedyaml:"-" json:"-", and merge both back into a singlecallbacks:object when serializing.parser.Referencealready exists (parser/common.go:88) withRef/Summary/Description, so the value type is off the shelf.Callbackswill miss referenced ones; today they cannot parse the document at all, so it is strictly an improvement.Acceptance
pass/path_item_servers_parameters.yamlparses and validates clean; the reference round-trips verbatim in both YAML and JSON.decodeFromMap. feat(parser,validator): support bare-boolean schemas for OAS 3.1+ #450 found the third silently dropping values rather than erroring; that trap is live here too.walkergains an additive handler if references should be walkable; existingCallbackHandlerbehaviour is unchanged.Context
Callbacks are rare in practice — none of the ten real-world specs in the corpus use them, and only two fixtures in the OAI 3.2 suite mention them. The cost of the gap is not frequency but blast radius: a document that merely contains one referenced callback fails to parse entirely, rather than degrading.
Files
parser/paths.go,parser/oas3.go,parser/common.go,internal/codegen/decode/,internal/codegen/deepcopy/,internal/driftguard/,walker/Context: design doc · plan doc