halo-dev/halo · error · SchemaViolationException

Failed to validate {gvk}

Error message

Failed to validate {gvk}

What it means

Thrown as a SchemaViolationException (HTTP 400) by JSONExtensionConverter.convertTo when the JSON serialization of an Extension fails the OpenAPI schema validator attached to its Scheme. The message is 'Failed to validate ' + groupVersionKind, and the exception carries the full ValidationResults so callers can inspect which fields failed. It occurs on create/update paths before persisting to the ExtensionStore.

Source

Thrown at application/src/main/java/run/halo/app/extension/JSONExtensionConverter.java:82

        var scheme = schemeManager.get(gvk);

        try {
            var convertedExtension = Optional.of(extension)
                    .map(item -> scheme.type().isAssignableFrom(item.getClass())
                            ? item
                            : objectMapper.convertValue(item, scheme.type()))
                    .orElseThrow();
            var validation = new ValidationData<>(extension);

            var extensionJsonNode = objectMapper.valueToTree(convertedExtension);
            var validator = getValidator(scheme);
            validator.validate(extensionJsonNode, validation);
            if (!validation.isValid()) {
                log.debug(
                        "Failed to validate Extension: {}, and errors were: {}",
                        extension.getClass(),
                        validation.results());
                throw new SchemaViolationException(extension.groupVersionKind(), validation.results());
            }

            var version = extension.getMetadata().getVersion();
            var storeName = buildStoreName(scheme, extension.getMetadata().getName());
            var data = objectMapper.writeValueAsBytes(extensionJsonNode);
            return new ExtensionStore(storeName, data, version);
        } catch (IOException e) {
            throw new ExtensionConvertException("Failed write Extension as bytes", e);
        } catch (ResolutionException e) {
            throw new RuntimeException("Failed to create schema validator", e);
        }
    }

    @Override
    public <E extends Extension> E convertFrom(Class<E> type, ExtensionStore extensionStore) {
        try {
            var extension = objectMapper.readValue(extensionStore.getData(), type);
            extension.getMetadata().setVersion(extensionStore.getVersion());

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Inspect exception.getErrors() (ValidationResults) to find the exact failing schema paths and fix the offending fields.
  2. Regenerate the extension's OpenAPI schema / re-register the Scheme after model changes so validation matches the new contract.
  3. Send a payload that matches the declared schema: correct types, all required fields, valid enum/pattern values.
  4. Validate the JSON against the Scheme's schema on the client side before calling create/update.

Example fix

// before: extension missing required spec field -> SchemaViolationException
// after:  populate spec per the Scheme schema, then client.create(extension)
Defensive patterns

Strategy: try-catch

Validate before calling

// validate the extension JSON against its Scheme schema before create
var validator = scheme.getSchemaValidator();
var node = objectMapper.valueToTree(extension);
var result = new ValidationData<>(extension);
validator.validate(node, result);
if (!result.isValid()) {
    throw new IllegalArgumentException("Schema invalid: " + result.results());
}

Try / catch

// inspect ValidationResults and surface the failing paths
try {
    client.create(extension);
} catch (SchemaViolationException e) {
    log.warn("Schema errors for {}: {}",
        extension.groupVersionKind(), e.getErrors());
    fixAndRetry(e.getErrors());
}

Prevention

When it happens

Trigger: client.create/update on any Extension (custom or built-in) whose JSON violates the registered Scheme's schema — required fields missing, wrong types, enum violations, pattern mismatches, or extra fields rejected by additionalProperties. Triggered whenever convertTo runs (create, update, and some internal writes).

Common situations: Custom extension model added/changed but Scheme/schema not regenerated; client (plugin or API caller) sends a field with the wrong type or omits a required field; GVK mismatch; OpenAPI schema drift after a version bump; manually constructed Unstructured with invalid shapes.

Related errors


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/abee43f205edf3cd. Report an issue: GitHub.