alibaba/spring-ai-alibaba · error · IllegalArgumentException
SkillRegistry must be provided. Use SkillsAgentHook to load
Error message
SkillRegistry must be provided. Use SkillsAgentHook to load skills.
What it means
SkillsInterceptor's private constructor requires a non-null SkillRegistry. The interceptor has nothing to resolve skills against without one, so building without a registry throws IllegalArgumentException and points you to SkillsAgentHook as the intended way to load skills.
Source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/skills/SkillsInterceptor.java:112
* {@value ReadSkillTool#READ_SKILL}. For each such call, the <i>skill_name</i> argument is recorded.
* Tools from {@link #getGroupedTools()} for those skill names are then added to the request's
* {@link ModelRequest#getDynamicToolCallbacks() dynamicToolCallbacks}.
*/
public class SkillsInterceptor extends ModelInterceptor {
private static final Logger logger = LoggerFactory.getLogger(SkillsInterceptor.class);
private final SkillRegistry skillRegistry;
private final Map<String, List<ToolCallback>> groupedTools;
private final Supplier<Map<String, List<ToolCallback>>> groupedToolsSupplier;
private final ToolCallbackResolver toolCallbackResolver;
private SkillsInterceptor(Builder builder) {
if (builder.skillRegistry == null) {
throw new IllegalArgumentException("SkillRegistry must be provided. Use SkillsAgentHook to load skills.");
}
this.skillRegistry = builder.skillRegistry;
this.groupedTools = builder.groupedTools != null
? builder.groupedTools
: Collections.emptyMap();
this.groupedToolsSupplier = builder.groupedToolsSupplier;
this.toolCallbackResolver = builder.toolCallbackResolver;
}
public static Builder builder() {
return new Builder();
}
@Override
public ModelResponse interceptModel(ModelRequest request, ModelCallHandler handler) {
List<SkillMetadata> skills = skillRegistry.listAll();
if (skills.isEmpty()) {View on GitHub (pinned to f82da0b50f)
Solutions
- Use SkillsAgentHook to load and register skills, which supplies the SkillRegistry
- Pass a non-null SkillRegistry to the SkillsInterceptor Builder before build()
- Check that the hook that populates the registry actually executed before interceptor creation
Example fix
// before SkillsInterceptor.builder().build(); // no skillRegistry // after new SkillsAgentHook(registryPath).register(); SkillsInterceptor.builder().skillRegistry(registry).build();
Defensive patterns
Strategy: validation
Validate before calling
if (registry == null) { throw new IllegalStateException("SkillRegistry not initialized; run SkillsAgentHook first"); }
SkillsInterceptor.builder().skillRegistry(registry).build(); Try / catch
try { interceptor = SkillsInterceptor.builder().build(); } catch (IllegalArgumentException e) { throw new IllegalStateException("Wire SkillsAgentHook before SkillsInterceptor", e); } Prevention
- Always register skills through SkillsAgentHook
- Construct interceptors after hook initialization in app lifecycle
- Add a startup check asserting the registry bean is non-null
When it happens
Trigger: Building a SkillsInterceptor via its Builder without calling the method that sets skillRegistry (or passing null), instead of using SkillsAgentHook to populate it.
Common situations: Manually constructing the interceptor instead of going through SkillsAgentHook; registry wiring removed during refactor; conditional registration where the hook never ran.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Emulator model is required
- MissingParameter
- CreateMCPServerError
- UpdateMCPServerError
- APP_COMPONENT_QUERYCONFIG_ERROR
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/0417a4597b8782cd.
Report an issue: GitHub.