Description
oapi-codegen version: v2.6.0
When a oneOf schema uses a discriminator and the variant schemas are defined via allOf (inheriting from a base schema with an optional field that gets narrowed to an enum in the variant), the generator correctly produces a pointer type for the discriminator field — but then generates From* / Merge* helper functions that assign a raw string literal to that pointer field. This produces code that does not compile.
Two mistakes occur in the same generated output:
- A plain untyped string constant is assigned to a pointer type (
*ResourceConflictErrorCode), which the compiler rejects.
- The already-generated typed constants (
ResourceExists, IdempotencyConflict) are not used — even if the field were non-pointer, a direct string literal assignment would still fail due to the named type.
Schema (minimal reproduction)
# errs.yml
components:
schemas:
ErrorResponse:
type: object
required: [error]
properties:
code:
type: string
error:
type: string
ResourceConflictError:
type: object
required: [code, error]
allOf:
- $ref: '#/components/schemas/ErrorResponse'
- properties:
code:
type: string
enum: [resource_exists]
example: resource_exists
IdempotencyConflictError:
type: object
required: [code, error]
allOf:
- $ref: '#/components/schemas/ErrorResponse'
- properties:
code:
type: string
enum: [idempotency_conflict]
example: idempotency_conflict
responses:
Conflict:
description: Conflict
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ResourceConflictError'
- $ref: '#/components/schemas/IdempotencyConflictError'
discriminator:
propertyName: code
mapping:
resource_exists: '#/components/schemas/ResourceConflictError'
idempotency_conflict: '#/components/schemas/IdempotencyConflictError'
Generated code (broken)
The generator emits typed constants and pointer-typed fields correctly:
const (
IdempotencyConflict IdempotencyConflictErrorCode = "idempotency_conflict"
ResourceExists ResourceConflictErrorCode = "resource_exists"
)
type ResourceConflictError struct {
Code *ResourceConflictErrorCode `json:"code,omitempty"`
Error string `json:"error"`
}
type IdempotencyConflictError struct {
Code *IdempotencyConflictErrorCode `json:"code,omitempty"`
Error string `json:"error"`
}
But the From* / Merge* helpers assign raw string literals to those pointer fields:
func (t *Conflict) FromResourceConflictError(v ResourceConflictError) error {
v.Code = "resource_exists" // ERROR: cannot use untyped string as *ResourceConflictErrorCode
...
}
func (t *Conflict) MergeResourceConflictError(v ResourceConflictError) error {
v.Code = "resource_exists" // ERROR: same
...
}
func (t *Conflict) FromIdempotencyConflictError(v IdempotencyConflictError) error {
v.Code = "idempotency_conflict" // ERROR: cannot use untyped string as *IdempotencyConflictErrorCode
...
}
func (t *Conflict) MergeIdempotencyConflictError(v IdempotencyConflictError) error {
v.Code = "idempotency_conflict" // ERROR: same
...
}
Compiler errors
cannot use "resource_exists" (untyped string constant) as *ResourceConflictErrorCode value in assignment
cannot use "idempotency_conflict" (untyped string constant) as *IdempotencyConflictErrorCode value in assignment
Root cause (hypothesis)
The generator does not honour the required: [code, error] constraint declared at the top level alongside allOf — it sees code as optional in the base ErrorResponse and generates a pointer field. The From*/Merge* template then generates a plain string literal assignment without accounting for either the pointer indirection or the named type, and without reusing the typed constants it already emitted earlier in the same file.
Description
oapi-codegen version: v2.6.0
When a
oneOfschema uses adiscriminatorand the variant schemas are defined viaallOf(inheriting from a base schema with an optional field that gets narrowed to an enum in the variant), the generator correctly produces a pointer type for the discriminator field — but then generatesFrom*/Merge*helper functions that assign a raw string literal to that pointer field. This produces code that does not compile.Two mistakes occur in the same generated output:
*ResourceConflictErrorCode), which the compiler rejects.ResourceExists,IdempotencyConflict) are not used — even if the field were non-pointer, a direct string literal assignment would still fail due to the named type.Schema (minimal reproduction)
Generated code (broken)
The generator emits typed constants and pointer-typed fields correctly:
But the
From*/Merge*helpers assign raw string literals to those pointer fields:Compiler errors
Root cause (hypothesis)
The generator does not honour the
required: [code, error]constraint declared at the top level alongsideallOf— it seescodeas optional in the baseErrorResponseand generates a pointer field. TheFrom*/Merge*template then generates a plain string literal assignment without accounting for either the pointer indirection or the named type, and without reusing the typed constants it already emitted earlier in the same file.