hibernate/hibernate-orm · error · IllegalArgumentException

key cannot be null or empty

Error message

key cannot be null or empty

What it means

StringJsonDocumentWriter.objectKey(String) emits a "key": pair while building the JSON document and refuses null or empty keys with an IllegalArgumentException. Hibernate reaches this while serializing a Java map or embeddable into a JSON column: an entry whose key (or attribute name) is null or the empty string cannot be represented as a JSON object member.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/format/StringJsonDocumentWriter.java:108

		this.appender.append( StringJsonDocumentMarker.ARRAY_START.getMarkerCharacter() );
		return this;
	}

	/**
	 * Callback to be called when the end of an array is encountered.
	 */
	@Override
	public JsonDocumentWriter endArray() {
		this.appender.append( StringJsonDocumentMarker.ARRAY_END.getMarkerCharacter() );
		this.processingStates.push( JsonProcessingState.ENDING_ARRAY );
		moveProcessingStateMachine();
		return this;
	}

	@Override
	public JsonDocumentWriter objectKey(String key) {
		if ( key == null || key.isEmpty() ) {
			throw new IllegalArgumentException( "key cannot be null or empty" );
		}

		if ( JsonProcessingState.OBJECT.equals( this.processingStates.getCurrent() ) ) {
			// we have started an object, and we are adding an item key: we do add a separator.
			this.appender.append( StringJsonDocumentMarker.SEPARATOR.getMarkerCharacter() );
		}
		this.appender.append( StringJsonDocumentMarker.QUOTE.getMarkerCharacter() );
		this.appender.append( key );
		this.appender.append( "\":" );
		moveProcessingStateMachine();
		return this;
	}

	/**
	 * Adds a separator if needed.
	 * The logic here is know if we have to prepend a separator
	 * as such, it must be called at the beginning of all methods
	 * Separator is to separate array items or key/value pairs in an object.

View on GitHub (pinned to fad1729dce)

Solutions

  1. Sanitize map keys before persisting: drop or rename null/empty entries (e.g. replace null with "")
  2. Validate in a @PrePersist/@PreUpdate listener or in the entity setter so bad maps never reach the writer
  3. If a null key must be represented, encode it as a sentinel string like "__null__"
  4. Catch IllegalArgumentException at flush to identify the offending entity and field

Example fix

// before
entity.setAttributes(userMap); // userMap contains null or "" keys -> flush fails
// after
Map<String, Object> safe = new LinkedHashMap<>();
userMap.forEach((k, v) -> {
    if (k != null && !k.isEmpty()) safe.put(k, v);
});
entity.setAttributes(safe);
Defensive patterns

Strategy: validation

Validate before calling

static Map<String, Object> sanitizeKeys(Map<String, Object> map) {
    Map<String, Object> out = new java.util.LinkedHashMap<>();
    map.forEach((k, v) -> {
        if (k == null || k.isEmpty()) return; // or remap: out.put("__null__", v)
        out.put(k, v);
    });
    return out;
}

entity.setAttributes(sanitizeKeys(rawMap));

Type guard

static boolean isValidJsonKey(String key) {
    return key != null && !key.isEmpty();
}

Try / catch

try {
    session.persist(entity);
    session.flush();
} catch (IllegalArgumentException e) {
    if ("key cannot be null or empty".equals(e.getMessage())) {
        throw new ValidationException("JSON map keys must be non-empty strings", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Flushing an entity whose JSON-mapped field contains a null or "" key: @JdbcTypeCode(SqlTypes.JSON) Map<String, Object> with a null/empty key entry, dynamic-map entities with a null map key, or any custom JsonDocumentWriter client calling objectKey(null)/objectKey("").

Common situations: Maps built from user input or Collectors.groupingBy(...) with null keys persisted as JSON; a HashMap with its single permitted null key sneaking in; map keys trimmed/generated into empty strings.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/763bd73dc3c1a695. Report an issue: GitHub.