conductor-oss/conductor · critical · IllegalStateException
Failed to read skill file: {e.getMessage()}
Error message
Failed to read skill file: {e.getMessage()} What it means
Thrown by readFile() as an IllegalStateException when an IOException occurs while streaming the skill's zip package. Unlike the IllegalArgumentExceptions around it, this indicates an unexpected I/O failure (e.g. corrupt or truncated zip data read back from the package store, stream closed mid-read) rather than a caller input mistake. The original IOException is attached as the cause.
Source
Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java:299
}
byte[] data =
readBounded(
zip,
maxPreviewBytes,
"Skill file is too large to preview: " + cleanPath);
boolean binary = isBinary(cleanPath, data);
return SkillFileContent.builder()
.path(cleanPath)
.contentType(contentType(cleanPath))
.size(data.length)
.binary(binary)
.content(binary ? null : new String(data, StandardCharsets.UTF_8))
.contentBase64(binary ? Base64.getEncoder().encodeToString(data) : null)
.build();
}
throw new IllegalArgumentException("Skill file not found: " + cleanPath);
} catch (IOException e) {
throw new IllegalStateException("Failed to read skill file: " + e.getMessage(), e);
}
}
@SuppressWarnings("unchecked")
public Map<String, Object> resolveRawConfig(Map<String, Object> skillRef) {
requireSkillStorage();
if (skillRef == null) {
throw new IllegalArgumentException("skillRef is required");
}
String name = requiredString(skillRef, "name");
String version = stringValue(skillRef.get("version"));
SkillDetail detail = get(name, version);
Map<String, Object> rawConfig = rawConfigForDetail(detail, new HashSet<>());
Object model = skillRef.get("model");
if (model instanceof String s && !s.isBlank()) {
rawConfig.put("model", s);
}
Object agentModels = skillRef.get("agentModels");View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Re-register the skill package so a fresh, intact zip is stored (DELETE then POST /register, or POST with the same checksum to restore).
- Check the package store / storage backend health and the stored handle's integrity.
- Inspect the caused-by IOException message for the specific read failure location.
Example fix
// no code fix — recover by re-uploading the package DELETE /api/skills/foo/versions/1.0.0 POST /api/skills/register (manifest + fresh package zip)
Defensive patterns
Strategy: try-catch
Try / catch
try { return skillRegistryService.readFile(name, version, path); }
catch (IllegalStateException e) {
if (e.getMessage().startsWith("Failed to read skill file")) {
// package storage corrupt: re-register the package, then retry
log.error("skill file read failed; package may be corrupt", e);
}
throw e;
} Prevention
- Monitor package store health and free space to avoid truncated writes.
- Re-register packages that fail to read so a known-good copy is stored.
When it happens
Trigger: GET /api/skills/{name}/versions/{version}/files?path=SKILL.md when the stored package bytes are corrupt or partially written, or when the underlying packageStore.read() returns truncated data that breaks ZipInputStream.
Common situations: Package store corruption after an interrupted write; a backend restart mid-store; filesystem or object-storage returning partial bytes; a zip that was never validly closed at upload time.
Related errors
- Failed to read skill package: {e.getMessage()}
- Skill package exceeds max file count of {maxFileCount}
- Skill package contains duplicate path: {path}
- Skill package contains oversized file: {path}
- Skill package exceeds max uncompressed size of {maxUncompres
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/085d71e1d456f77f.
Report an issue: GitHub.