alibaba/spring-ai-alibaba · error · IllegalArgumentException
skill_name and skill_path must refer to the same skill
Error message
skill_name and skill_path must refer to the same skill
What it means
When both skill_name and skill_path are provided, the tool resolves both via the registry and verifies they denote the same skill (compared by name). If the name and path point to different skills it throws this IllegalArgumentException to prevent reading an ambiguous/unintended skill.
Solutions
- Pass only one of skill_name or skill_path, not both, unless you are sure they match.
- Rebuild/refresh the SkillRegistry so path mappings reflect current skill names.
- Verify the registered name equals the skill at the given path before sending both fields.
Example fix
// before
String content = tool.apply("{\"skill_name\": \"summarizer\", \"skill_path\": \"/skills/translator\"}");
// after
String content = tool.apply("{\"skill_name\": \"summarizer\"}"); Defensive patterns
Strategy: validation
Validate before calling
if (req.skillName != null && req.skillPath != null) {
var byName = registry.get(req.skillName);
var byPath = registry.getByPath(req.skillPath);
if (byName.isPresent() && byPath.isPresent() && !byName.get().getName().equals(byPath.get().getName())) {
throw new IllegalArgumentException("skill_name/skill_path mismatch");
}
} Type guard
boolean consistent(SkillRegistry reg, String name, String path) {
return name == null || path == null ||
reg.get(name).equals(reg.getByPath(path));
} Try / catch
try { return tool.apply(input); } catch (IllegalArgumentException e) { return "Ambiguous skill reference: " + e.getMessage(); } Prevention
- Pass only skill_name or only skill_path unless both are verified.
- Refresh the registry after renaming/moving skills on disk.
- Sanitize model-supplied arguments instead of trusting combined name+path.
When it happens
Trigger: Invoking the read_skill tool with skill_name="a" and skill_path pointing to skill "b"'s directory; stale registry state where the path mapping changed after the model cached a pair of arguments.
Common situations: LLM combining a remembered skill name with a guessed path; skills renamed or moved on disk so path and name diverge; copy-paste mistakes in hand-built tool calls.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Either skill_name or skill_path is required
- 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/25efe5b9708798dc.
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:111
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);
}
private static String normalize(String value) {
return StringUtils.hasText(value) ? value.trim() : null;
}
/**
* Request structure for reading a skill.
*/
public static class ReadSkillRequest {View on GitHub (pinned to f82da0b50f)