hibernate/hibernate-orm · error · IllegalStateException

unexpected quote read in current processing state

Error message

unexpected quote read in current processing state {}

What it means

While pulling items, the reader consumed a '"' character, but the internal state machine is in a state where a quoted token is illegal — only STARTING_ARRAY, ARRAY, STARTING_OBJECT, OBJECT and OBJECT_KEY_NAME accept one (e.g. state NONE before any '{' or '[' was seen). The message appends the offending state, e.g. 'unexpected quote read in current processing state NONE'. Hibernate is rejecting structurally invalid JSON.

Solutions

  1. Inspect the exact column value that fails and make the document object- or array-rooted, with quotes only around keys and string values
  2. Fix the writer (ETL job, other application, manual UPDATE) to emit strict JSON via a real serializer
  3. Pre-validate values on write with a strict parser (see validationCode)
  4. Catch IllegalStateException around the Hibernate read so the bad row fails with a meaningful message instead of breaking hydration blind

Example fix

-- before: column holds a bare JSON string
UPDATE entity_table SET json_col = '"hello"';
-- after: object-rooted document
UPDATE entity_table SET json_col = '{"msg":"hello"}';
Defensive patterns

Strategy: try-catch

Validate before calling

// run before storing into a JSON-mapped column
static boolean isStrictJsonRooted(String candidate) {
    try {
        com.fasterxml.jackson.databind.JsonNode n =
                new com.fasterxml.jackson.databind.ObjectMapper().readTree(candidate);
        return n.isObject() || n.isArray();
    } catch (Exception e) {
        return false;
    }
}

Try / catch

try {
    return session.createQuery(...).getResultList();
} catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("unexpected quote read")) {
        throw new DataQualityException("JSON column holds a non object/array-rooted document", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: next() reading a QUOTE marker while the state is NONE, ENDING_OBJECT or ENDING_ARRAY: a top-level string document like "abc" with no wrapping {} or []; trailing text after the root closes like {} "x"; a stray quote where the grammar requires ':', ',', '}' or ']'.

Common situations: JSON columns populated by hand or by another service that stores a bare serialized string instead of an object/array-rooted document; concatenating two JSON documents into one column value; storing the double-encoded JSON-string representation of an object.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at hibernate-core/src/main/java/org/hibernate/type/format/StringJsonDocumentReader.java:192

					//   - if we are in the middle of an object :
					//        - if we just hit ':' that's a quoted value
					//        - if we just hit ',' that's a quoted key
					switch ( this.processingStates.getCurrent() ) {
						case STARTING_ARRAY:
							//this.processingStates.push( JsonProcessingState.ARRAY );
							return JsonDocumentItemType.VALUE;
						case ARRAY:
							return JsonDocumentItemType.VALUE;
						case STARTING_OBJECT:
							//this.processingStates.push( JsonProcessingState.OBJECT );
							//this.processingStates.push( JsonProcessingState.OBJECT_KEY_NAME );
							return JsonDocumentItemType.VALUE_KEY;
						case OBJECT: // we are processing object attribute value elements
							return JsonDocumentItemType.VALUE;
						case OBJECT_KEY_NAME: // we are processing object elements key
							return JsonDocumentItemType.VALUE_KEY;
						default:
							throw new IllegalStateException( "unexpected quote read in current processing state " +
															this.processingStates.getCurrent() );
					}
				case KEY_VALUE_SEPARATOR:  // that's the start of an attribute value
					//assert this.processingStates.getCurrent() == JsonProcessingState.OBJECT_KEY_NAME;
					// flush the OBJECT_KEY_NAME
					//this.processingStates.pop();
					break;
				case SEPARATOR:
					// unless we are processing an array, following SEPARATOR that will a key
					break;
				case OTHER:
					// here we are in front of a boolean, a null or a numeric value.
					// if none of these cases we're going to raise IllegalStateException
					// put back what we've read
					moveBufferPosition(-1);
					final int valueSize = consumeNonStringValue();
					if (valueSize == -1) {
						throw new IllegalStateException( "Unrecognized marker: " + StringJsonDocumentMarker.markerOf(

View on GitHub (pinned to fad1729dce)