OpenAPITools/openapi-generator · error · IllegalArgumentException

{} must be one of SKIP, FAIL, or NONE (to emit no annotation

Error message

{} must be one of SKIP, FAIL, or NONE (to emit no annotation), but was: {}

What it means

JsonAnnotationPolicyUtils.resolveManualJsonSetterNulls validates the per-property 'x-jackson-json-setter-nulls' vendor extension used by the spring and kotlin-spring generators. Valid values are SKIP, FAIL, or NONE (emit no @JsonSetter annotation); null or blank also means NONE. Any other token throws IllegalArgumentException, prefixed with the extension name so the offending spec location is identifiable.

Source

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

     *
     * @param rawValue      the raw vendor extension value set directly on the property in the spec
     * @param extensionName the vendor extension key, used in the error message
     * @return the normalized {@link JsonSetterNullsMode}: {@code SKIP}/{@code FAIL} to emit that annotation, or
     * {@link JsonSetterNullsMode#NONE} when the override means "emit no annotation" ({@code NONE}/blank)
     * @throws IllegalArgumentException when the override is not {@code SKIP}, {@code FAIL}, or {@code NONE}
     */
    public static JsonSetterNullsMode resolveManualJsonSetterNulls(Object rawValue, String extensionName) {
        if (rawValue == null) {
            return JsonSetterNullsMode.NONE;
        }
        String trimmed = rawValue.toString().trim();
        if (trimmed.isEmpty()) {
            return JsonSetterNullsMode.NONE;
        }
        try {
            return JsonSetterNullsMode.valueOf(trimmed.toUpperCase(java.util.Locale.ROOT));
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(extensionName
                    + " must be one of SKIP, FAIL, or NONE (to emit no annotation), but was: " + rawValue);
        }
    }

    /**
     * Resolve the {@code @JsonSetter(nulls = ...)} annotation for a property into the
     * {@code x-has-json-setter-nulls-skip}/{@code -fail} vendor extension the templates emit, mutating
     * {@code property.vendorExtensions} and {@code model.imports} in place. Precedence (mirrors
     * {@link #resolveJsonIncludePolicy}):
     * <ol>
     *   <li>A per-property {@code x-jackson-json-setter-nulls} override in the spec always wins and is honored
     *       unconditionally (regardless of {@code generateJsonSetterNullsAnnotations}, required/nullable,
     *       {@code openApiNullable}, or {@code failModeSupported}).</li>
     *   <li>Otherwise the automatic optional-non-nullable mode from
     *       {@link #resolveJsonSetterNullsMode(TriStateBoolean, boolean, boolean, boolean, boolean, JsonSetterNullsMode)}.</li>
     * </ol>
     *
     * @param model                              the model owning {@code property}, whose imports may be extended

View on GitHub (pinned to fcec517be3)

Solutions

  1. Set the extension to SKIP, FAIL, or NONE exactly (underscores not needed; case-insensitive).
  2. Remove the extension to inherit the generator-wide optionalNonNullPropertyJsonSetterNulls / openApiNullable-derived behavior.
  3. Grep the spec for x-jackson-json-setter-nulls and check each value against the three allowed tokens.

Example fix

# before (openapi.yaml)
          x-jackson-json-setter-nulls: skip-nulls

# after
          x-jackson-json-setter-nulls: SKIP
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

const isJsonSetterNulls = (v: unknown): v is 'SKIP' | 'FAIL' | 'NONE' =>
  typeof v === 'string' && ['SKIP','FAIL','NONE'].includes(v.trim().toUpperCase());

Prevention

When it happens

Trigger: Adding x-jackson-json-setter-nulls: skip-nulls, ignore, or ALWAYS to a schema property and generating with -g spring / -g kotlin-spring. Matching is trim + uppercase + valueOf, so 'skip' and 'Skip' parse, but hyphenated or free-text values do not.

Common situations: Spec authors paraphrasing Jackson documentation ('nulls = Nulls.SKIP' pasted verbatim); consistent-value policies where one property in a big spec has a typo; converting JSON examples with lowercase-hyphen style into YAML extension values.

Related errors


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