alibaba/spring-ai-alibaba · error · IllegalArgumentException
Either skill_name or skill_path is required
Error message
Either skill_name or skill_path is required
What it means
readSkillContent requires at least one identifier for the skill: either skill_name or skill_path in the request. If both are absent (or blank after normalization) it throws this IllegalArgumentException instead of attempting an ambiguous lookup.
Solutions
- Include either "skill_name" (registered name) or "skill_path" (file path) in the tool-call arguments.
- Validate the request object before calling apply/readSkillContent and return a corrective message to the model.
- Improve the tool description so the model reliably passes one of the two identifiers.
Example fix
// before
String content = tool.apply("{}"); // neither field set -> throws
// after
String content = tool.apply("{\"skill_name\": \"pdf-reader\"}"); Defensive patterns
Strategy: validation
Validate before calling
com.fasterxml.jackson.databind.JsonNode args = mapper.readTree(toolInput);
if (!args.hasNonNull("skill_name") && !args.hasNonNull("skill_path")) {
return "Error: provide either skill_name or skill_path";
} Type guard
boolean hasIdentifier(ReadSkillRequest r) { return r != null && (r.skillName != null || r.skillPath != null); } Try / catch
try { return tool.apply(input); } catch (IllegalArgumentException e) { return "Bad arguments: " + e.getMessage(); } Prevention
- Document both tool parameters clearly in the tool description.
- Validate tool-call JSON before invoking apply.
- Return corrective feedback to the LLM so it retries with a proper identifier.
When it happens
Trigger: An LLM invokes the read_skill tool with an empty or missing arguments object, or supplies unrelated keys so both skillName and skillPath normalize to null.
Common situations: Model hallucinating tool arguments or omitting them entirely; a caller constructing ReadSkillRequest with neither field set; JSON deserialization dropping fields with different names than expected.
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
- skill_name and skill_path must refer to the same skill
- At least one fallback model must be specified
- Elastic search index name must be provided
- Invalid experiment status
- key cannot be empty
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/c2bbfaa315fc18cf.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/hook/skills/ReadSkillTool.java:102
catch (IllegalStateException e) {
logger.warn("Skill not found: {}", e.getMessage());
return "Error: " + e.getMessage();
}
catch (IOException e) {
logger.error("Error reading skill content: {}", e.getMessage(), e);
return "Error reading skill file: " + e.getMessage();
}
catch (Exception e) {
logger.error("Unexpected error reading skill: {}", e.getMessage(), e);
return "Error: " + e.getMessage();
}
}
private String readSkillContent(ReadSkillRequest request) throws IOException {
String skillName = normalize(request != null ? request.skillName : null);
String skillPath = normalize(request != null ? request.skillPath : null);
if (skillName == null && skillPath == null) {
throw new IllegalArgumentException("Either skill_name or skill_path is required");
}
if (skillName != null && skillPath != null) {
SkillMetadata skillByName = skillRegistry.get(skillName)
.orElseThrow(() -> new IllegalStateException("Skill not found: " + skillName));
SkillMetadata skillByPath = skillRegistry.getByPath(skillPath)
.orElseThrow(() -> new IllegalStateException("Skill not found: " + skillPath));
if (!skillByName.getName().equals(skillByPath.getName())) {
throw new IllegalArgumentException("skill_name and skill_path must refer to the same skill");
}
return skillRegistry.readSkillContent(skillByName.getName());
}
if (skillName != null) {
return skillRegistry.readSkillContent(skillName);
}
return skillRegistry.readSkillContentByPath(skillPath);
}View on GitHub (pinned to f82da0b50f)