alibaba/spring-ai-alibaba · error · IOException
SKILL.md not found at: {}
Error message
SKILL.md not found at: {} What it means
SkillMetadata.loadFullContent lazily reads SKILL.md from the skill's directory and caches it. If the file does not exist at skillPath/SKILL.md, an IOException is thrown because a skill is defined by its SKILL.md file and cannot be loaded without it.
Source
Thrown at spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/skills/SkillMetadata.java:98
}
public String getFullContent() {
return fullContent;
}
public List<String> getAllowedTools() {
return allowedTools;
}
public void setAllowedTools(List<String> allowedTools) {
this.allowedTools = allowedTools == null ? List.of() : List.copyOf(allowedTools);
}
public String loadFullContent() throws IOException {
if (fullContent == null) {
Path skillFile = Path.of(skillPath, "SKILL.md");
if (!Files.exists(skillFile)) {
throw new IOException("SKILL.md not found at: " + skillFile);
}
String rawContent = Files.readString(skillFile);
fullContent = removeFrontmatter(rawContent);
}
return fullContent;
}
private String removeFrontmatter(String content) {
if (!content.startsWith("---")) {
return content;
}
int endIndex = content.indexOf("---", 3);
if (endIndex == -1) {
return content;
}
View on GitHub (pinned to f82da0b50f)
Solutions
- Verify Files.exists(Path.of(skillPath, "SKILL.md")) before loading and fix skillPath to point at the skill directory
- Check for case-sensitive filename mismatches (must be exactly SKILL.md)
- If packaging resources, ensure SKILL.md is copied into the built artifact (Maven resources include)
- Use an absolute path or resolve relative paths against the correct base directory at runtime
Example fix
// before
SkillMetadata meta = SkillMetadata.builder().name("x").skillPath("skills/x/SKILL.md")...build();
// after: point at the directory containing SKILL.md
SkillMetadata meta = SkillMetadata.builder().name("x").skillPath("skills/x")...build(); Defensive patterns
Strategy: validation
Validate before calling
Path f = Path.of(skillPath, "SKILL.md");
if (!Files.isRegularFile(f)) throw new IllegalArgumentException("Missing SKILL.md at " + f); Type guard
boolean hasSkillManifest(String skillPath) {
return Files.isRegularFile(Path.of(skillPath, "SKILL.md"));
} Try / catch
try { content = skill.loadFullContent(); } catch (IOException e) { if (e.getMessage().startsWith("SKILL.md not found")) { content = fallbackContent(skill.getName()); } else throw e; } Prevention
- Point skillPath at the directory containing SKILL.md, not the file itself
- Verify SKILL.md is included in packaged resources before deployment
- Use absolute or classpath-resolved paths; watch out for filename casing on Linux
When it happens
Trigger: Calling loadFullContent (directly or via readSkillContent/readSkillContentByPath) when the directory at skillPath lacks a SKILL.md file — wrong path, missing packaging, or path pointing at the file itself instead of its directory.
Common situations: Deployed jar missing skill resource directories; skill folder copied without SKILL.md; wrong casing (skill.md) on case-sensitive filesystems; path configured relative to a working directory different from runtime.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Got error when creating files
- Got error when creating files
- Failed to create temp directory for converter
- Failed to store item to file system
- Failed to delete item from file system
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/f4d70aebedfb13c1.
Report an issue: GitHub.