Skip to content

feat(openapi3): typed validation error clusters (combined: #1171-#1179)#1180

Merged
fenollp merged 12 commits into
getkin:masterfrom
oasdiff:feat/validation-error-clusters-combined
May 9, 2026
Merged

feat(openapi3): typed validation error clusters (combined: #1171-#1179)#1180
fenollp merged 12 commits into
getkin:masterfrom
oasdiff:feat/validation-error-clusters-combined

Conversation

@reuvenharrison

@reuvenharrison reuvenharrison commented May 9, 2026

Copy link
Copy Markdown
Contributor

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

Was Cluster / leaves
#1171 MutuallyExclusiveFieldsError — example.value/externalValue, mediaType.example/examples, license.url/identifier, link.operationId/operationRef, schema.readOnly/writeOnly
#1172 ForbiddenFieldError — header.name, header.in, OAuth flow auth/token URLs
#1173 RequiredFieldError leaves — parameter.name, responses non-empty, apiKey securityScheme.name
#1174 ServerURLTemplateError — mismatched braces, undeclared variables (count + name flavours)
#1175 EitherFieldRequiredError + SchemaItemsRequired — example value-or-externalValue, link operationId-or-Ref, schema.items required when type=array
#1176 RequiredFieldError leaves — doc-root info, paths (3.0), jsonSchemaDialect URI
#1177 SchemaBothFormsExclusive — additionalProperties, unevaluatedItems, unevaluatedProperties (boolean + schema both set)
#1178 ExactlyOneFieldError + SingleEntryContentError — parameter/header content+schema sites
#1179 WebhookNilError — nil pathitem in T.Validate webhook walk

Each PR's commit is preserved as a separate commit on this branch (with one small docs: regenerate openapi3.txt commit at the tip and a test: use require.ErrorContains per repo lint follow-up that was on #1178). Author / date / commit message of each original commit are preserved.

Verification

  • go test ./... clean across all packages
  • All cluster types and leaves grep-verifiable in openapi3/validation_error.go
  • Backward-compat error strings preserved (existing string-matching consumers unaffected)
  • .github/docs/openapi3.txt regenerated via ./docs.sh

#1171-#1179 are closed in favour of this PR.

…eld pairs

Converts four mutual-exclusion sites:
- example.value vs externalValue
- mediaType.example vs examples
- license.url vs identifier
- link.operationId vs operationRef
…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)
…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.
@fenollp fenollp merged commit e8145f8 into getkin:master May 9, 2026
5 checks passed
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants