{"record":{"id":"17190ba4dd89e74b","repo":"hibernate/hibernate-orm","slug":"error-attempting-to-apply-attributeconverter-17190b","errorCode":null,"errorMessage":"Error attempting to apply AttributeConverter: \" + re.getMessage()","messagePattern":"Error attempting to apply AttributeConverter: \" \\+ re\\.getMessage\\(\\)","errorType":"exception","errorClass":"PersistenceException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/AttributeConverterBean.java","lineNumber":116,"sourceCode":"\t\t}\n\t\tcatch (PersistenceException pe) {\n\t\t\tthrow pe;\n\t\t}\n\t\tcatch (RuntimeException re) {\n\t\t\tthrow new PersistenceException( \"Error attempting to apply AttributeConverter\", re );\n\t\t}\n\t}\n\n\t@Override\n\tpublic R toRelationalValue(O domainForm) {\n\t\ttry {\n\t\t\treturn attributeConverterBean.getBeanInstance().convertToDatabaseColumn( domainForm );\n\t\t}\n\t\tcatch (PersistenceException pe) {\n\t\t\tthrow pe;\n\t\t}\n\t\tcatch (RuntimeException re) {\n\t\t\tthrow new PersistenceException( \"Error attempting to apply AttributeConverter: \" + re.getMessage(), re );\n\t\t}\n\t}\n\n\t@Override\n\tpublic JavaType<? extends AttributeConverter<O, R>> getConverterJavaType() {\n\t\treturn converterJavaType;\n\t}\n\n\t@Override\n\tpublic JavaType<O> getDomainJavaType() {\n\t\treturn domainJavaType;\n\t}\n\n\t@Override\n\tpublic JavaType<R> getRelationalJavaType() {\n\t\treturn jdbcJavaType;\n\t}\n","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/converter/internal/AttributeConverterBean.java#L98-L134","documentation":"Hibernate wraps any non-PersistenceException RuntimeException thrown by your AttributeConverter.convertToDatabaseColumn while translating a domain value into its relational form for writing. This variant comes from AttributeConverterBean (managed-bean converter wrapper), so it fires on the write path: INSERT/UPDATE statements and converter-bound query parameters. The original exception is attached as the cause.","triggerScenarios":"Persisting or updating an entity whose @Convert attribute's convertToDatabaseColumn(domainForm) throws - e.g. an NPE because the entity value is null, a switch without a default on a newly added enum constant, or formatting code that fails on the value.","commonSituations":"Null attribute not guarded in the converter (Hibernate does call the converter with null in several paths); a new enum constant added without extending the converter's mapping; a formatter (DateTimeFormatter, DecimalFormat) receiving an unexpected value; stricter Hibernate 6+ converter type resolution after an upgrade.","solutions":["Inspect the cause via getCause() to locate the failing line in convertToDatabaseColumn","Guard the null case and cover every enum constant (add a default branch)","Bind the parameter with the right API if the failure happens on a query parameter (setParameter with the converter class)","Write a failing unit test that calls the converter directly with null and every domain constant"],"exampleFix":"// before\n@Override\npublic String convertToDatabaseColumn(Status status) {\n    return switch (status) {\n        case ACTIVE -> \"A\";\n        case CLOSED -> \"C\";\n    }; // NPE on null, IllegalArgument on future constants\n}\n// after\n@Override\npublic String convertToDatabaseColumn(Status status) {\n    if (status == null) {\n        return null;\n    }\n    return switch (status) {\n        case ACTIVE -> \"A\";\n        case CLOSED -> \"C\";\n    };\n}","handlingStrategy":"try-catch","validationCode":"// validate in setters/service code before flush can reach the converter\nvoid setStatus(Status s) {\n    if (s != null && StatusConverter.codeOf(s) == null) throw new IllegalArgumentException(\"Unmapped: \" + s);\n    this.status = s;\n}","typeGuard":"static boolean isConvertible(Status s) {\n    return s == null || switch (s) { case ACTIVE, CLOSED -> true; default -> false; };\n}","tryCatchPattern":"try {\n    session.persist(entity);\n    session.flush(); // force converter execution here for a precise failure point\n} catch (PersistenceException e) {\n    Throwable cause = e;\n    while (cause.getCause() != null) cause = cause.getCause();\n    log.error(\"Converter failed on attribute value {} of {}\", entity.getStatus(), entity.getClass());\n    // surface cause to user / abort transaction\n}","preventionTips":["Null-check the domain value first in every convertToDatabaseColumn","Cover every enum constant and add a default branch when the domain type can grow","Call session.flush() in integration tests right after persist so converter failures surface at the exact operation","Keep converters pure and side-effect free"],"tags":["hibernate","orm","jpa","attribute-converter","persistence-exception","flush"],"backgroundTag":"jpa-attribute-converter-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}