spring-projects/spring-ai · error · IOException
Invalid filename for file '': ''
Error message
Invalid filename for file '': ''
What it means
resolveSafeChildPath rejects filenames that resolve to '.' or '..' (or otherwise normalize to the target directory itself), throwing this IOException with the raw name. It prevents a download from overwriting the target directory or escaping it via relative-name tricks. The single-segment rule has already passed; this is the dot-segment guard.
Source
Thrown at models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicSkillsResponseHelper.java:169
throw new IOException("Invalid filename for file '" + fileId + "': null or blank");
}
Path name;
try {
name = Path.of(rawName);
}
catch (InvalidPathException ex) {
throw new IOException("Invalid filename for file '" + fileId + "': " + rawName, ex);
}
if (name.isAbsolute() || name.getRoot() != null) {
throw new IOException("Invalid filename for file '" + fileId + "': absolute path '" + rawName + "'");
}
if (name.getNameCount() != 1) {
throw new IOException(
"Invalid filename for file '" + fileId + "': must be a single path segment '" + rawName + "'");
}
String only = name.getName(0).toString();
if (only.equals(".") || only.equals("..")) {
throw new IOException("Invalid filename for file '" + fileId + "': '" + rawName + "'");
}
// One extra hardening check to make sure nothing fell through the cracks above
// (future tweaks to the rules, odd platform path quirks, etc.).
Path base = targetDir.toAbsolutePath().normalize();
Path resolved = base.resolve(only).normalize();
if (!resolved.startsWith(base)) {
throw new IOException(
"Invalid filename for file '" + fileId + "': resolves outside target directory '" + rawName + "'");
}
return resolved;
}
private static void extractFileIdsFromBashResult(BashCodeExecutionToolResultBlock resultBlock,
List<String> fileIds) {
BashCodeExecutionToolResultBlock.Content content = resultBlock.content();
if (content.isBashCodeExecutionResultBlock()) {
for (BashCodeExecutionOutputBlock outputBlock : content.asBashCodeExecutionResultBlock().content()) {View on GitHub (pinned to 98a7beda4f)
Solutions
- Filter out directory entries ('.'/'..') from the API file list before calling filePath.
- Validate the filename client-side: skip files whose name is null, blank, or equals '.'/'..'.
- Sanitize by generating a fallback name (e.g. file-<fileId>.bin) when the reported name is not a real filename.
- Catch the IOException and log/skip the offending entry.
Example fix
// before
helper.filePath(fileId, name);
// after
if (name == null || name.isBlank() || name.equals(".") || name.equals("..")) {
return; // skip non-file entry
}
helper.filePath(fileId, name); Defensive patterns
Strategy: validation
Validate before calling
static boolean isRealFileName(String name) {
return name != null && !name.isBlank()
&& !name.equals(".") && !name.equals("..");
} Type guard
static String requireFileName(String name) {
if (!isRealFileName(name)) throw new IllegalArgumentException("Not a filename: " + name);
return name;
} Try / catch
try {
Path p = helper.filePath(fileId, name);
} catch (IOException e) {
log.warn("Skipping non-file entry {}", name, e);
} Prevention
- Filter directory entries out of file listings before download.
- Sanitize or regenerate fallback names for blank/self-referential names.
- Treat API filenames as untrusted data, never as trusted paths.
When it happens
Trigger: The API-reported filename is '.', '..', './' or '.\' (e.g. empty-ish or self-referential names after normalization), so the extracted single segment equals '.' or '..'.
Common situations: Directory entries included in a skills listing and passed through as files; truncated or empty name fields that normalize to '.'; unusual zip/skill archives that contain directory markers.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Invalid filename for file '': must be a single path segment
- Invalid filename for file '': resolves outside target direct
- Request failed
- Could not read content length
- Failed to write request body
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/e169f567eec657d8.
Report an issue: GitHub.