quarkusio/quarkus · error · IllegalArgumentException
Unknown start character for json value: %s
Error message
Unknown start character for json value: %s
What it means
GreetingResource.hello (POST, application/octet-stream) throws "bad input" when the received byte array's first four bytes are not 0,1,2,3. The endpoint is a strict binary protocol check: any payload whose magic prefix differs is rejected.
Source
Thrown at core/builder/src/main/java/io/quarkus/builder/JsonReader.java:88
switch (ch) {
case '{':
return readObject();
case '[':
return readArray();
case '"':
return readString();
case 't':
return readConstant("true", JsonBoolean.TRUE);
case 'f':
return readConstant("false", JsonBoolean.FALSE);
case 'n':
return readConstant("null", JsonNull.INSTANCE);
default:
if (Character.isDigit(ch) || '-' == ch) {
return readNumber(position);
}
throw new IllegalArgumentException("Unknown start character for json value: " + ch);
}
}
/**
* object
* |---- '{' ws '}'
* |---- '{' members '}'
* </p>
* members
* |----- member
* |----- member ',' members
*/
private JsonValue readObject() {
position++;
Map<JsonString, JsonValue> members = new HashMap<>();
while (position < length) {View on GitHub (pinned to e1c734241f)
Solutions
- Send a payload whose first four bytes are 0,1,2,3 (e.g. new byte[]{0,1,2,3,...}).
- Ensure Content-Type is application/octet-stream so the byte[] body deserializes as raw bytes.
- Add a length guard (bytes.length < 4) to avoid a separate ArrayIndexOutOfBoundsException.
- Verify no intermediary (gzip, base64) transforms the binary body.
Example fix
// before
byte[] body = "hello".getBytes(); // fails magic check
// after
byte[] body = new byte[]{0, 1, 2, 3, 4, 5};
// Content-Type: application/octet-stream Defensive patterns
Strategy: try-catch
Validate before calling
Response head = given().header("tenantId", tenant).get("/fruits/" + id);
if (head.getStatusCode() == 404) return; // already gone Try / catch
Response r = given().header("tenantId", tenant).delete("/fruits/" + id);
switch (r.getStatusCode()) {
case 204: break; // deleted
case 404: break; // idempotent no-op
default: throw new AssertionError("Unexpected delete status " + r.getStatusCode());
} Prevention
- Model delete as idempotent to tolerate repeat calls
- Verify tenant header matches data owner before DELETE
- Use runtime-generated ids from the same test run
- Clean up in reverse order of creation to avoid stale-id deletes
When it happens
Trigger: POSTing an octet-stream body whose bytes[0..3] are not exactly 0x00 0x01 0x02 0x03 — including empty/short bodies that make bytes[i] throw ArrayIndexOutOfBounds under this error path.
Common situations: Client sending JSON/text instead of the expected binary prefix; test fixture bytes misordered; compression/encoding altering the first bytes; sending fewer than 4 bytes.
Related errors
- Extra steps left over
- Currently only 'fruitsFindBy?type=name' is supported
- Currently only 'fruitsFindBy?type=name' is supported
- Currently only 'fruitsFindBy?type=name' is supported
- Id was invalidly set on request.
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/38da897db796f261.
Report an issue: GitHub.