feat(openapi3): typed validation error clusters (combined: #1171-#1179)#1180
Merged
fenollp merged 12 commits intoMay 9, 2026
Merged
Conversation
…eld pairs Converts four mutual-exclusion sites: - example.value vs externalValue - mediaType.example vs examples - license.url vs identifier - link.operationId vs operationRef
…ExclusiveFieldsError
…ields Converts four 'field MUST NOT be set in this context' sites: - header.name (given by the headers map key) - header.in (implicitly 'header') - OAuth flow authorizationUrl (wrong flow type) - OAuth flow tokenUrl (wrong flow type)
…es non-empty, apiKey securityScheme.name
…e failures
Converts three server URL template sites:
- mismatched { and }
- undeclared variables (template/Variables count mismatch)
- undeclared variables (declared name not in URL template)
…red leaf - example.value or externalValue - link.operationId or operationRef - schema.items required when type=array (RequiredFieldError leaf)
… jsonSchemaDialect URI Three new RequiredFieldError leaves at the doc-validation root: - info (must be an object) - paths (must be an object — 3.0 only) - jsonSchemaDialect (must be an absolute URI with a scheme)
…ma fields set both ways Three sites in schema.go where a BoolSchema-typed field has both forms set: - additionalProperties - unevaluatedItems - unevaluatedProperties
…rs for parameter/header content+schema Four sites: - parameter.go content/schema must be exactly one - parameter.go content map must contain at most one entry - header.go content/schema must be exactly one - header.go content map must contain at most one entry
…k walk Single-site cluster carrying the offending webhook key name.
This was referenced May 9, 2026
Closed
This was referenced May 13, 2026
fenollp
pushed a commit
that referenced
this pull request
May 14, 2026
* feat(openapi3): typed context errors for Validate() wrapper chain
Replaces the 14 fmt.Errorf wrap sites in Validate() with three typed
error types carrying their context as structured fields:
- SectionContextError{Section, Cause} — wraps an error inside one of
the top-level document sections (info, paths, components, security,
servers, tags, externalDocs, webhooks, jsonSchemaDialect)
- PathContextError{Path, Cause} — wraps an error inside a
specific path
- OperationContextError{Method, Cause} — wraps an error inside a
specific HTTP-method operation
Continues the typed-validation-error work from #1166 and #1180:
those PRs typed the leaf errors; this one types the wrapper layers
that carry doc-tree position around them.
Why: today, callers that want to render context separately (which
section a finding lives in, which path, which operation) have to
parse the rendered error string with regex. errors.As against typed
wrappers is the structured equivalent.
Backward compatibility: Error() strings are byte-identical to the
fmt.Errorf wrappers they replace. Existing consumers parsing the
rendered text continue to work unchanged. The typed extraction is
purely additive.
Wrap sites converted:
- openapi3.go: 9 sections (info, paths, components, security,
servers, tags, externalDocs, webhooks, jsonSchemaDialect)
- paths.go: per-path wrapper (PathContextError)
- path_item.go: per-operation wrapper (OperationContextError)
- operation.go, tag.go, schema.go: 3 additional externalDocs sites
(also use SectionContextError{Section: "external docs"})
Tests cover Error() format byte-stability, Unwrap chain walking,
errors.As extraction from a three-layer chain (section + path +
operation), and arbitrary non-typed inner causes. All existing
tests pass unchanged across openapi2, openapi3, openapi3conv,
openapi3filter, openapi3gen, and the routers — confirming the
rendered strings are stable.
.github/docs/openapi3.txt regenerated via docs.sh.
* refactor(openapi3): rename context errors to *ValidationError
Addresses review feedback on #1183:
- SectionContextError -> SectionValidationError
- PathContextError -> PathValidationError
- OperationContextError -> OperationValidationError
The new names tie these positional wrappers to the ValidationError
family they belong to (base ValidationError, cluster types, leaves).
Also renames the file to sit in that namespace:
section_context_error.go -> validation_error_context.go (+ _test.go).
No behavior change: Error() strings and Unwrap() chains are untouched.
.github/docs/openapi3.txt regenerated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Per @fenollp's request on #1177, this combines the nine stacked typed-validation-error PRs (#1171-#1179) into a single branch to avoid rebase churn.
What's combined
MutuallyExclusiveFieldsError— example.value/externalValue, mediaType.example/examples, license.url/identifier, link.operationId/operationRef, schema.readOnly/writeOnlyForbiddenFieldError— header.name, header.in, OAuth flow auth/token URLsRequiredFieldErrorleaves — parameter.name, responses non-empty, apiKey securityScheme.nameServerURLTemplateError— mismatched braces, undeclared variables (count + name flavours)EitherFieldRequiredError+SchemaItemsRequired— example value-or-externalValue, link operationId-or-Ref, schema.items required when type=arrayRequiredFieldErrorleaves — doc-root info, paths (3.0), jsonSchemaDialect URISchemaBothFormsExclusive— additionalProperties, unevaluatedItems, unevaluatedProperties (boolean + schema both set)ExactlyOneFieldError+SingleEntryContentError— parameter/header content+schema sitesWebhookNilError— nil pathitem in T.Validate webhook walkEach PR's commit is preserved as a separate commit on this branch (with one small
docs: regenerate openapi3.txtcommit at the tip and atest: use require.ErrorContains per repo lintfollow-up that was on #1178). Author / date / commit message of each original commit are preserved.Verification
go test ./...clean across all packagesopenapi3/validation_error.go.github/docs/openapi3.txtregenerated via./docs.sh#1171-#1179 are closed in favour of this PR.