quarkusio/quarkus · error · RuntimeException

String too large to record

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.

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.

Appendix: 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)