{"record":{"id":"f080260708686efc","repo":"alibaba/spring-ai-alibaba","slug":"chatoptions-type-should-be-consistent-with-th","errorCode":null,"errorMessage":"chatOptions type ({}) should be consistent with the default options type ({}) from ChatModel/ChatClient for proper merging.","messagePattern":"chatOptions type \\((.+?)\\) should be consistent with the default options type \\((.+?)\\) from ChatModel/ChatClient for proper merging\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/DefaultBuilder.java","lineNumber":355,"sourceCode":"\t}\n\n\t/**\n\t * Merge source options (from ChatModel or ChatClient) with agent-level chatOptions.\n\t * Agent-level options take precedence. Uses ModelOptionsUtils.merge with the source\n\t * options type as the target.\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tprivate static ChatOptions mergeSourceOptionsWithAgentOptions(ChatOptions sourceOptions,\n\t\t\tChatOptions agentOptions) {\n\t\tif (sourceOptions == null) {\n\t\t\treturn agentOptions;\n\t\t}\n\t\tif (agentOptions == null) {\n\t\t\treturn sourceOptions;\n\t\t}\n\t\tClass<?> sourceOptionsClass = sourceOptions.getClass();\n\t\tif (sourceOptionsClass == agentOptions.getClass()) {\n\t\t\tlogger.warn(\n\t\t\t\t\t\"chatOptions type ({}) should be consistent with the default options type ({}) from ChatModel/ChatClient for proper merging.\",\n\t\t\t\t\tagentOptions.getClass().getName(), sourceOptionsClass.getName());\n\t\t}\n//\t\tClass<ChatOptions> targetClass = (Class<ChatOptions>) sourceOptionsClass;\n//\t\tChatOptions agentAsSourceType = ModelOptionsUtils.copyToTarget(agentOptions, ChatOptions.class, targetClass);\n\t\treturn (ChatOptions) ModelOptionsUtils.merge(agentOptions, sourceOptions, sourceOptionsClass);\n\t}\n\n\t/**\n\t * Get the default ChatOptions from a ChatModel via reflection (e.g. {@code getDefaultOptions()}).\n\t * @param model the ChatModel instance (may be null)\n\t * @return the model's default options, or null if not set or reflection fails\n\t */\n\tprivate static ChatOptions getChatModelDefaultOptions(ChatModel model) {\n\t\tif (model == null) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/DefaultBuilder.java#L337-L373","documentation":"When merging runtime chatOptions with the agent's default options, DefaultBuilder warns if the runtime options class differs from the source (ChatModel/ChatClient default) options class, because ModelOptionsUtils.merge relies on both being the same concrete type for proper merging; the merge still proceeds via reflection but may drop options.","triggerScenarios":"effectiveOptions is called with a runtime ChatOptions subclass (e.g. DashScopeChatOptions) different from the model's default options class (e.g. OpenAiChatOptions), so agentOptions.getClass() != sourceOptions.getClass().","commonSituations":"Mixing model providers: agent configured for DashScope defaults but request passes OpenAI-style options; passing generic ChatOptions where provider-specific options are the default; multiple ChatModels on the classpath picking a different default.","solutions":["Pass runtime options of the same concrete class as the model's default options","Change the underlying ChatModel/ChatClient so its default options type matches the options you supply","Use ModelOptionsUtils.copyToTarget to convert the runtime options to the default options class before the call","Remove the mismatched per-request options and configure everything on the model defaults"],"exampleFix":"// before\nChatOptions opts = new OpenAiChatOptions(); // model defaults are DashScopeChatOptions\nagent.call(options -> opts);\n// after\nDashScopeChatOptions opts = DashScopeChatOptions.builder().build(); // same type as model defaults\nagent.call(options -> opts);","handlingStrategy":"type-guard","validationCode":"if (runtimeOptions != null && defaultOptions != null && runtimeOptions.getClass() != defaultOptions.getClass()) { log.warn(\"Options type mismatch: {} vs {}\", runtimeOptions.getClass(), defaultOptions.getClass()); }","typeGuard":"static boolean sameOptionsType(ChatOptions a, ChatOptions b) { return a == null || b == null || a.getClass() == b.getClass(); }","tryCatchPattern":null,"preventionTips":["Always build per-request options with the provider-specific class matching the configured ChatModel","Avoid mixing providers' ChatOptions implementations in one application without conversion","Add an assertion/test that agent options class equals model default options class"],"tags":["options-merging","type-mismatch","chat-options"],"backgroundTag":"type-mismatch","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}