{"record":{"id":"9a9654b841707b42","repo":"chinabugotech/hutool","slug":"unsupported-model","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/AIServiceFactory.java","lineNumber":72,"sourceCode":"\t */\n\tpublic static AIService getAIService(final AIConfig config) {\n\t\treturn getAIService(config, AIService.class);\n\t}\n\n\t/**\n\t * 获取AI服务\n\t *\n\t * @param config AIConfig配置\n\t * @param clazz AI服务类\n\t * @return clazz对应的AI服务类实例\n\t * @since 5.8.38\n\t * @param <T> AI服务类\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T extends AIService> T getAIService(final AIConfig config, final Class<T> clazz) {\n\t\tfinal AIServiceProvider provider = providers.get(config.getModelName().toLowerCase());\n\t\tif (provider == null) {\n\t\t\tthrow new IllegalArgumentException(\"Unsupported model: \" + config.getModelName());\n\t\t}\n\n\t\tfinal AIService service = provider.create(config);\n\t\tif (!clazz.isInstance(service)) {\n\t\t\tthrow new AIException(\"Model service is not of type: \" + clazz.getSimpleName());\n\t\t}\n\n\t\treturn (T) service;\n\t}\n}\n","sourceCodeStart":54,"sourceCodeEnd":83,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-ai/src/main/java/cn/hutool/ai/AIServiceFactory.java#L54-L83","documentation":"Thrown by AIServiceFactory.getAIService when no AIServiceProvider is registered for config.getModelName(). The factory builds its provider map from Java SPI (ServiceLoaderUtil.load(AIServiceProvider.class)), keyed by provider.getServiceName().toLowerCase(). If that key is absent, the requested vendor is not on the classpath as a registered SPI provider. Valid vendor keys are the ModelName enum values: hutool, deepSeek, openai, doubao, grok, ollama, gemini (matched case-insensitively).","triggerScenarios":"Calling AIUtil.getAIService(config) or AIServiceFactory.getAIService(config, clazz) where config.getModelName() returns a string with no matching AIServiceProvider on the classpath. Typical: passing the concrete model id (\"gpt-4\", \"deepseek-chat\") instead of the vendor name (\"openai\", \"deepSeek\"), or a typo, or the model submodule jar is missing.","commonSituations":"Shading the app into a fat jar without a ServicesResourceTransformer / ServicesAppendingTransformer (META-INF/services merge lost); depending on hutool-ai but not pulling in the specific model module; passing a custom AIConfig whose getModelName() does not match any registered provider; Spring Boot fat-jar packaging that drops SPI files.","solutions":["Pass the vendor name exactly as defined in ModelName (e.g. ModelName.OPENAI.getValue() -> \"openai\"), not the model id.","Confirm the model submodule (e.g. hutool-ai model openai classes) is on the runtime classpath.","If using maven-shade-plugin, configure ServicesResourceTransformer so META-INF/services/cn.hutool.ai.core.AIServiceProvider is merged, not overwritten.","In Spring Boot fat jars, verify BOOT-INF/lib contains the module and that the SPI resource survived repackaging.","List providers at startup via ServiceLoader.load(AIServiceProvider.class) to see which names are actually registered."],"exampleFix":"// before\nAIConfig cfg = new AIConfigBuilder(\"gpt-4\").setApiKey(k).build();\nAIUtil.getAIService(cfg); // -> Unsupported model: gpt-4\n\n// after\nAIConfig cfg = new AIConfigBuilder(ModelName.OPENAI.getValue()) // \"openai\"\n    .setApiKey(k)\n    .setModel(\"gpt-4\")   // concrete model goes here\n    .build();\nAIUtil.getOpenAIService(cfg);","handlingStrategy":"validation","validationCode":"// Validate vendor name against registered providers BEFORE calling the factory\nString vendor = ModelName.OPENAI.getValue(); // prefer enum\njava.util.List<String> registered = new java.util.ArrayList<>();\nfor (AIServiceProvider p : java.util.ServiceLoader.load(AIServiceProvider.class)) {\n    registered.add(p.getServiceName().toLowerCase());\n}\nif (!registered.contains(vendor.toLowerCase())) {\n    throw new IllegalStateException(\n        \"No AIServiceProvider for '\" + vendor + \"'. Registered: \" + registered);\n}","typeGuard":null,"tryCatchPattern":"try {\n    AIService s = AIUtil.getAIService(config);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Unsupported model\")) {\n        // config.getModelName() not registered -> fix vendor string / classpath / SPI merge\n    }\n    throw e;\n}","preventionTips":["Always source the vendor string from the ModelName enum, never hardcode a model id.","In shade builds, configure ServicesResourceTransformer for META-INF/services.","Add a startup smoke test that ServiceLoader.load(AIServiceProvider.class) lists your vendor."],"tags":["spi","classloader","configuration","factory"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}