Skip to content

Uncompilable code generated when enum is placed on a type: array schema #2497

Description

@ChalamaiahReddy

oapi-codegen version: v2.7.2

Summary

When an OpenAPI schema has "type": "array" with a top-level "enum" key, oapi-codegen generates two simultaneous errors that make the output file fail to compile:

  1. A const block is emitted for a slice type — Go does not permit const declarations for slice types.
  2. The string values in the const block are written as bare unquoted identifiers instead of quoted string literals.

Both failures are always produced together from the same trigger and require the same fix.

Root cause

oapi-codegen's enum codegen path assumes the underlying Go type will always be a scalar (string, int, etc.). When enum appears on a schema whose Go representation is a slice ([]string), the generator enters that same path with a slice type and produces invalid Go.

The spec pattern that triggers this is:

{
  "type": "array",
  "items": { "type": "string" },
  "enum": ["router", "general-purpose", "scan-host", "embedded"]
}

This is distinct from the standard pattern — enum on a type: string schema — which oapi-codegen handles correctly:

{
  "type": "string",
  "enum": ["router", "general-purpose", "scan-host", "embedded"]
}

Steps to reproduce

Create a minimal spec file bug.yaml:

openapi: "3.0.3"
info:
  title: Bug Repro
  version: "1.0"
paths: {}
components:
  schemas:
    SystemTypes:
      type: array
      items:
        type: string
      enum:
        - router
        - general-purpose
        - scan-host
        - embedded

Generate:

oapi-codegen --config=config.yaml --generate=types,skip-fmt bug.yaml

Generated output (v2.7.2)

// SystemTypes defines model for SystemTypes.
type SystemTypes = []string

// Defines values for SystemTypes.
const (
  SystemTypesEmbedded       SystemTypes = embedded        // ❌ unquoted bare identifier
  SystemTypesGeneralPurpose SystemTypes = general-purpose // ❌ unquoted + hyphen is subtraction operator
  SystemTypesRouter         SystemTypes = router          // ❌ unquoted bare identifier
  SystemTypesScanHost       SystemTypes = scan-host       // ❌ unquoted + hyphen is subtraction operator
)

Compiler errors

cannot declare const of type []string (non-comparable or non-constant type)
undefined: embedded
undefined: general
undefined: router
undefined: scan

Expected output

Since Go does not permit const declarations for slice types, compile-time enforcement is not achievable. The closest valid equivalent is a helper function:

// SystemTypes defines model for SystemTypes.
type SystemTypes = []string

// ValidSystemTypesElement reports whether s is a known element value for SystemTypes.
func ValidSystemTypesElement(s string) bool {
    switch s {
    case "router", "general-purpose", "scan-host", "embedded":
        return true
    default:
        return false
    }
}

Alternatively, the generator may skip enum codegen for array-typed schemas entirely and emit a warning, leaving validation to the caller. Either outcome is acceptable — the current behavior (uncompilable const block) is not.

Real-world spec source

Observed with the Tenable Vulnerability Management API (v2.7.2 generation). Example schema: Export_Assets_response-assets-chunk-v1.properties.system_types.

Verified that specs which use the standard pattern (enum inside items, or enum on a type: string schema) and they are working as expected

Note on spec conformance

The triggering pattern — enum at the array level rather than inside items — is technically non-standard per JSON Schema. The semantically correct form is to place enum inside items. However, this pattern appears in real-world vendor-provided specs that users have no control over.

The core invariant that must hold unconditionally is: a code generator must never silently produce Go code that does not compile. We consider any of the following acceptable resolutions:

  1. Detect that the resolved Go type is a slice, suppress const generation, and optionally emit a comment listing the known values.
  2. Emit a warning identifying the schema as non-standard and skip enum codegen for it.
  3. Return a hard error pointing to the offending schema so the user can correct the spec.

Silently emitting a const block for a slice type requires manual patching before the generated file can be used.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions