OpenAPITools/openapi-generator · error · IllegalArgumentException

{} must be a valid com.fasterxml.jackson.annotation.JsonIncl

Error message

{} must be a valid com.fasterxml.jackson.annotation.JsonInclude.Include value (ALWAYS, NON_NULL, NON_ABSENT, NON_EMPTY, NON_DEFAULT, USE_DEFAULTS, CUSTOM), or NONE to emit no annotation, but was: {}

What it means

JsonAnnotationPolicyUtils.resolveManualJsonIncludePolicy (used by the spring and kotlin-spring generators) validates a per-property 'x-jackson-json-include-policy' vendor extension from the spec. The value must be a Jackson JsonInclude.Include constant — ALWAYS, NON_NULL, NON_ABSENT, NON_EMPTY, NON_DEFAULT, USE_DEFAULTS, CUSTOM — or NONE/blank meaning 'emit no annotation'. Anything else throws IllegalArgumentException, with the extension name prefixed so you know where to look.

Source

Thrown at modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/JsonAnnotationPolicyUtils.java:84

    private JsonAnnotationPolicyUtils() {
    }

    /**
     * Validate and normalize a manual per-property {@code x-jackson-json-include-policy} override.
     *
     * @param rawPolicy       the raw vendor extension value set directly on the property in the spec
     * @param extensionName   the vendor extension key, used in the error message (kept generator-agnostic)
     * @return the normalized (upper-case) policy name to emit, or {@code null} when the override means
     * "emit no annotation" ({@code NONE}/blank), in which case the caller must drop the extension.
     * @throws IllegalArgumentException when the override is not a valid {@code JsonInclude.Include} value.
     */
    public static String resolveManualJsonIncludePolicy(Object rawPolicy, String extensionName) {
        JsonIncludePolicy parsed;
        try {
            parsed = JsonIncludePolicy.parse(rawPolicy);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(extensionName
                    + " must be a valid com.fasterxml.jackson.annotation.JsonInclude.Include value "
                    + "(ALWAYS, NON_NULL, NON_ABSENT, NON_EMPTY, NON_DEFAULT, USE_DEFAULTS, CUSTOM), or NONE to emit "
                    + "no annotation, but was: " + rawPolicy);
        }
        if (parsed == null || !parsed.isEmitted()) {
            return null;
        }
        return parsed.name();
    }

    /**
     * Validate and normalize the {@code optionalNonNullPropertyJsonInclude} config option value.
     *
     * @param policy      the raw config option value (may be {@code null}, in which case the default
     *                    {@code NON_NULL} is returned)
     * @param optionName  the config option name, used in the error message (kept generator-agnostic)
     * @return the normalized (upper-case) policy name: one of {@code NON_NULL}, {@code NON_EMPTY},
     * {@code NON_DEFAULT}, {@code NONE}.

View on GitHub (pinned to fcec517be3)

Solutions

  1. Use an exact JsonInclude.Include enum name in the spec: NON_NULL, NON_EMPTY, NON_DEFAULT, ALWAYS, NON_ABSENT, USE_DEFAULTS, CUSTOM (underscores, case-insensitive).
  2. Use NONE or an empty value when you want no @JsonInclude emitted for that property.
  3. Search your spec for x-jackson-json-include-policy and validate each occurrence against the enum list in the error message.

Example fix

# before (openapi.yaml)
components:
  schemas:
    User:
      properties:
        email:
          type: string
          x-jackson-json-include-policy: non-null

# after
          x-jackson-json-include-policy: NON_NULL
Defensive patterns

Strategy: validation

Validate before calling

// Node: validate x-jackson-json-include-policy values in the spec
const ALLOWED = new Set(['ALWAYS','NON_NULL','NON_ABSENT','NON_EMPTY','NON_DEFAULT','USE_DEFAULTS','CUSTOM','NONE','']);
const check = (o) => { for (const [k, v] of Object.entries(o ?? {})) {
  if (k === 'x-jackson-json-include-policy' && !ALLOWED.has(String(v).trim().toUpperCase()))
    throw new Error(`invalid x-jackson-json-include-policy: ${v}`);
  if (v && typeof v === 'object') check(v);
}};
check(require('./openapi.json'));

Type guard

const JSON_INCLUDE_POLICIES = ['ALWAYS','NON_NULL','NON_ABSENT','NON_EMPTY','NON_DEFAULT','USE_DEFAULTS','CUSTOM','NONE'] as const;
type JsonIncludePolicy = typeof JSON_INCLUDE_POLICIES[number];
const isJsonIncludePolicy = (v: unknown): v is JsonIncludePolicy =>
  typeof v === 'string' &&
  (JSON_INCLUDE_POLICIES as readonly string[]).includes(v.trim().toUpperCase());

Try / catch

catch (IllegalArgumentException e) {
    // message names the extension and the bad value — fix the spec and regenerate
    throw new RuntimeException("Spec fix needed: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Adding x-jackson-json-include-policy: non-null (hyphen instead of underscore), if_present, or NEVER to a schema property in the OpenAPI spec and generating with -g spring or -g kotlin-spring. Values are matched case-insensitively after trim, but only exact enum names parse.

Common situations: Writing Jackson annotation values from memory with hyphens or wrong casing of words ('non-null', 'use-defaults'); copying Jackson 2.x vs 3.x enum names; a misspelled extension value silently present in a large spec until generation fails.

Related errors


AI-assisted analysis of OpenAPITools/openapi-generator@fcec517be3 (2026-08-22). Data as JSON: /api/errors/a776336ac3fac048. Report an issue: GitHub.