spring-projects/spring-ai · error · IOException
Invalid filename for file '': null or blank
Error message
Invalid filename for file '': null or blank
What it means
AnthropicSkillsResponseHelper.resolveSafeChildPath validates filenames returned by the model/API before using them as path components. If the raw filename is null or blank, it throws IOException to prevent writing to an empty/invalid path. Filenames come from model-influenced metadata and are explicitly untrusted, so every rule (non-blank, relative, single segment, inside targetDir) is enforced with an IOException.
Source
Thrown at models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicSkillsResponseHelper.java:151
Path filePath = resolveSafeChildPath(targetDir, metadata.filename(), fileId);
Files.write(filePath, content);
savedPaths.add(filePath);
}
}
return savedPaths;
}
/**
* Validate an API-provided filename and resolve it to a child of {@code targetDir}.
* Rejects null/blank names, absolute paths, names containing path separators or
* {@code .}/{@code ..} segments, and names that resolve outside {@code targetDir}.
* Filenames come from model-influenced API metadata and must not be trusted as safe
* path components.
*/
static Path resolveSafeChildPath(Path targetDir, @Nullable String rawName, String fileId) throws IOException {
if (rawName == null || rawName.isBlank()) {
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 + "'");View on GitHub (pinned to 98a7beda4f)
Solutions
- Skip or reject the file entry and log the fileId instead of attempting to resolve a path for it.
- Verify your response-mapping class actually binds the filename field (check @JsonProperty/field names against the API response).
- Fetch fresh file metadata for the fileId to obtain a valid name before resolving paths.
- Add a fallback name (e.g. derived from fileId) only if it is safe and acceptable for your storage layout.
Example fix
// before
Path p = resolveSafeChildPath(targetDir, fileEntry.name(), fileEntry.id());
// after
if (fileEntry.name() == null || fileEntry.name().isBlank()) {
log.warn("Skipping file {} with missing name", fileEntry.id());
return null;
}
Path p = resolveSafeChildPath(targetDir, fileEntry.name(), fileEntry.id()); Defensive patterns
Strategy: try-catch
Validate before calling
if (entry.name() == null || entry.name().isBlank()) {
log.warn("Skipping file {} with null/blank name", entry.id());
return;
} Type guard
static boolean hasUsableName(AnalyzedFile entry) {
return entry.name() != null && !entry.name().isBlank();
} Try / catch
try {
Path p = AnthropicSkillsResponseHelper.resolveSafeChildPath(targetDir, rawName, fileId);
Files.copy(in, p);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("null or blank")) {
log.warn("File {} has no usable filename; skipped", fileId);
} else throw e;
} Prevention
- Validate that response-mapping binds the filename field before processing entries.
- Treat missing names as skip-and-log, never as empty-string paths.
- Re-fetch metadata when name is absent but the file is required.
When it happens
Trigger: Processing a skills/file API response whose file entry has a null or empty/whitespace-only name field; deserialization dropping the name property; resolving a child path for a file entry that only carries a fileId without a name.
Common situations: API responses with missing 'name' JSON fields mapped to null; upstream schema changes renaming the field; partial responses where a file was created without a name; mapping code that copies only id but not name.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid filename for file '':
- Maximum of 8 skills per request. Provided:
- Invalid filename for file '': absolute path ''
- Unsupported media type: . Supported types are: images (image
- Unsupported media data type: . Expected byte[] or String.
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/940e687832c546ec.
Report an issue: GitHub.