quarkusio/quarkus · error · RuntimeException

String too large to record: ${param}

Error message

String too large to record: ${param}

What it means

Recorded String parameters are emitted as JVM ldc constants, which are limited to 65535 UTF-8 bytes by the class file format. Quarkus rejects any String longer than that at recording time because it could not produce valid bytecode for it.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java:697

                    ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                        // If the value is a proxy, it may be non-null at build time but become null
                        // when we actually create the value during initialization;
                        // so we need to use 'ofNullable' and not 'of' here.
                        return method.invokeStaticMethod(ofMethod(Optional.class, "ofNullable", Optional.class, Object.class),
                                context.loadDeferred(res));
                    }
                };
            } else {
                return new DeferredArrayStoreParameter(param, expectedType) {
                    @Override
                    ResultHandle createValue(MethodContext context, MethodCreator method, ResultHandle array) {
                        return method.invokeStaticMethod(ofMethod(Optional.class, "empty", Optional.class));
                    }
                };
            }
        } else if (param instanceof String) {
            if (((String) param).length() > 65535) {
                throw new RuntimeException("String too large to record: " + param);
            }
            return new DeferredParameter() {
                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    return method.load((String) param);
                }
            };
        } else if (param instanceof URL) {
            String url = ((URL) param).toExternalForm();
            return new DeferredParameter() {
                @Override
                ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHandle array) {
                    AssignableResultHandle value = method.createVariable(URL.class);
                    try (TryBlock et = method.tryBlock()) {
                        et.assign(value, et.newInstance(MethodDescriptor.ofConstructor(URL.class, String.class), et.load(url)));
                        try (CatchBlockCreator malformed = et.addCatch(MalformedURLException.class)) {
                            malformed.throwException(RuntimeException.class, "Malformed URL", malformed.getCaughtException());
                        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Do not pass the large string through the recorder; write it to a file at build time and pass the file path, loading contents at runtime
  2. Store the data as a classpath resource and read it from the runtime code instead of recording it
  3. Chunk the string into pieces under 65535 chars and reassemble in the recorder/runtime, though resource approach is preferred
  4. Compress the payload (e.g. base64 of gzip) only if it then fits under the limit
  5. If this comes from a config value, reduce the value size or move it out of recorded configuration

Example fix

// before: huge string via recorder
recorder.setSchema(hugeSchemaJson);
// after: write to file at build time, pass path
Path p = generatedResourcesDir.resolve("schema.json");
Files.writeString(p, hugeSchemaJson);
recorder.setSchemaLocation(p.toString());
Defensive patterns

Strategy: validation

Validate before calling

if (value != null && value.length() > 65535) {
    throw new IllegalArgumentException(
        "Value exceeds JVM constant-pool limit (65535); pass a resource path instead: " + value.length());
}
recorder.setValue(value);

Type guard

static boolean isRecordableString(String s) {
    return s == null || s.length() <= 65535;
}

Try / catch

try {
    recorder.setValue(largeString);
} catch (RuntimeException e) {
    if (e.getMessage().startsWith("String too large")) {
        Path f = outDir.resolve("payload.txt");
        Files.writeString(f, largeString);
        recorder.setValueFromFile(f.toString());
    } else { throw e; }
}

Prevention

When it happens

Trigger: Passing a String argument longer than 65535 characters to a recorder method — e.g. embedded JSON, base64 blobs, generated SQL, PEM/keystore content, or a whole template body.

Common situations: Embedding a large certificate/keystore or serialized payload via a recorder; config values that ballooned; tests generating very large strings; setting schema/index definitions as a single recorded string.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/c3a96bc488bcf660. Report an issue: GitHub.