{"record":{"id":"cb01da967c136396","repo":"spring-projects/spring-ai","slug":"clonenotsupportedexception-wrapped-runtimeexcepti","errorCode":null,"errorMessage":"CloneNotSupportedException (wrapped RuntimeException)","messagePattern":"CloneNotSupportedException \\(wrapped RuntimeException\\)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/DefaultChatOptionsBuilder.java","lineNumber":56,"sourceCode":"\n\tprotected @Nullable Double temperature;\n\n\tprotected @Nullable Integer topK;\n\n\tprotected @Nullable Double topP;\n\n\tpublic DefaultChatOptionsBuilder() {\n\t}\n\n\t@Override\n\tpublic B clone() {\n\t\ttry {\n\t\t\tB copy = (B) super.clone();\n\t\t\tcopy.stopSequences = this.stopSequences == null ? null : new ArrayList<>(this.stopSequences);\n\t\t\treturn copy;\n\t\t}\n\t\tcatch (CloneNotSupportedException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tprotected B self() {\n\t\treturn (B) this;\n\t}\n\n\t@Override\n\tpublic B model(@Nullable String model) {\n\t\tthis.model = model;\n\t\treturn self();\n\t}\n\n\t@Override\n\tpublic B frequencyPenalty(@Nullable Double frequencyPenalty) {\n\t\tthis.frequencyPenalty = frequencyPenalty;\n\t\treturn self();","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/DefaultChatOptionsBuilder.java#L38-L74","documentation":"DefaultChatOptionsBuilder.clone() calls super.clone() and wraps any CloneNotSupportedException in a RuntimeException. Because the builder implements Cloneable this should never happen, so the wrapped exception indicates an internal JVM-level clone failure rather than a caller mistake.","triggerScenarios":"Invoking clone() on a DefaultChatOptionsBuilder (or subclass B) whose concrete class hierarchy fails Object.clone()'s Cloneable check.","commonSituations":"Practically only seen with custom subclasses of the builder that do not propagate Cloneable, or exotic bytecode/proxy frameworks stripping the interface.","solutions":["Ensure your builder subclass (and all superclasses) implements Cloneable.","Prefer constructing a fresh builder (options.builder()/mutate()) instead of relying on clone().","If you control the code, override clone() to copy fields manually and avoid Object.clone()."],"exampleFix":"// before\nDefaultChatOptionsBuilder copy = builder.clone();\n// after\nDefaultChatOptionsBuilder copy = DefaultChatOptionsBuilder.builder().from(builder.build());","handlingStrategy":"type-guard","validationCode":"if (!(builder instanceof Cloneable)) { /* don't call clone() */ }","typeGuard":"boolean cloneable(Object o) { return o instanceof Cloneable; }","tryCatchPattern":"try { return builder.clone(); } catch (RuntimeException e) { return DefaultChatOptionsBuilder.builder().from(builder.build()); }","preventionTips":["Avoid clone(); use the builder's copy/from pattern instead","Keep builder subclasses Cloneable if you rely on clone()","Don't proxy or bytecode-enhance option builders in ways that drop interfaces"],"tags":["clone","internal","options-builder"],"backgroundTag":"internal-invariant-violation","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}