{"record":{"id":"d49d7985e4e2faaf","repo":"chinabugotech/hutool","slug":"unsupported-model-d49d79","errorCode":null,"errorMessage":"Unsupported model: ","messagePattern":"Unsupported model: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java","lineNumber":42,"sourceCode":" *\n * @author elichow\n * @since 5.8.38\n */\npublic class AIConfigBuilder {\n\n\tprivate final AIConfig config;\n\n\t/**\n\t * 构造\n\t *\n\t * @param modelName 模型厂商的名称（注意不是指具体的模型）\n\t */\n\tpublic AIConfigBuilder(final String modelName) {\n\t\ttry {\n\t\t\t// 获取配置类\n\t\t\tfinal Class<? extends AIConfig> configClass = AIConfigRegistry.getConfigClass(modelName);\n\t\t\tif (configClass == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Unsupported model: \" + modelName);\n\t\t\t}\n\n\t\t\t// 使用反射创建实例\n\t\t\tfinal Constructor<? extends AIConfig> constructor = configClass.getDeclaredConstructor();\n\t\t\tconfig = constructor.newInstance();\n\t\t} catch (final Exception e) {\n\t\t\tthrow new RuntimeException(\"Failed to create AIConfig instance\", e);\n\t\t}\n\t}\n\n\t/**\n\t * 设置apiKey\n\t *\n\t * @param apiKey apiKey\n\t * @return config\n\t * @since 5.8.38\n\t */\n\tpublic synchronized AIConfigBuilder setApiKey(final String apiKey) {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-ai/src/main/java/cn/hutool/ai/core/AIConfigBuilder.java#L24-L60","documentation":"Thrown by the AIConfigBuilder constructor when AIConfigRegistry.getConfigClass(modelName) returns null. The registry is populated from Java SPI (ServiceLoaderUtil.load(AIConfig.class)) keyed by config.getModelName().toLowerCase(). A null result means no AIConfig implementation is registered for that vendor name. This is the config-side mirror of error 0.","triggerScenarios":"Calling new AIConfigBuilder(\"claude\") or any vendor not among hutool/deepSeek/openai/doubao/grok/ollama/gemini; passing the concrete model id instead of the vendor name; the model submodule jar (which carries both the AIConfig SPI entry and the config class) is absent from the classpath.","commonSituations":"Fat-jar shading that lost META-INF/services/cn.hutool.ai.core.AIConfig; typo in the vendor string; only depending on hutool-ai core without a model module; passing uppercase or mixed-case incorrectly is NOT the cause (lookup is case-insensitive) but a wrong vendor string is.","solutions":["Use a ModelName enum value: new AIConfigBuilder(ModelName.OLLAMA.getValue()).","Ensure the target model module is a dependency (it provides the AIConfig SPI registration).","Configure the shade plugin with ServicesResourceTransformer to merge META-INF/services entries.","Call AIConfigRegistry.getConfigClass(name) at startup to confirm registration before building."],"exampleFix":"// before\nnew AIConfigBuilder(\"gpt-4o\"); // -> Unsupported model: gpt-4o\n\n// after\nnew AIConfigBuilder(ModelName.OPENAI.getValue()).setModel(\"gpt-4o\");","handlingStrategy":"validation","validationCode":"// Confirm the config class is registered before building\nString vendor = ModelName.OPENAI.getValue();\nif (AIConfigRegistry.getConfigClass(vendor) == null) {\n    throw new IllegalStateException(\n        \"No AIConfig registered for \" + vendor + \"; check the module dependency / SPI\");\n}\nnew AIConfigBuilder(vendor);","typeGuard":null,"tryCatchPattern":"try {\n    return new AIConfigBuilder(vendor);\n} catch (RuntimeException e) {\n    Throwable root = e.getCause() != null ? e.getCause() : e;\n    if (root instanceof IllegalArgumentException\n        && root.getMessage().startsWith(\"Unsupported model\")) {\n        // vendor not registered -> fix classpath / shade SPI\n    }\n    throw e;\n}","preventionTips":["Derive the constructor argument from ModelName enum values.","Verify META-INF/services/cn.hutool.ai.core.AIConfig survives packaging.","Assert AIConfigRegistry.getConfigClass(vendor) != null at boot."],"tags":["spi","classloader","configuration","builder"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}