conductor-oss/conductor · error · IllegalArgumentException

Skill manifest is required

Error message

Skill manifest is required

What it means

Thrown by register() (via parseManifest) when the manifestJson argument is null or blank. The manifest is the @RequestPart("manifest") of the register multipart request and must be a non-empty JSON document. Without it there is no metadata to validate or version against.

Source

Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/service/SkillRegistryService.java:402

            if (metadataDao.find(name, version).isPresent()) {
                return version;
            }
            // Allow a checksum prefix in place of an exact version.
            for (SkillDetail detail : metadataDao.listVersions(name)) {
                if (detail.getChecksum() != null && detail.getChecksum().startsWith(version)) {
                    return detail.getVersion();
                }
            }
            return version;
        }
        return metadataDao
                .latestVersion(name)
                .orElseThrow(() -> new IllegalArgumentException("Skill not found: " + name));
    }

    private Map<String, Object> parseManifest(String manifestJson) {
        if (manifestJson == null || manifestJson.isBlank()) {
            throw new IllegalArgumentException("Skill manifest is required");
        }
        try {
            return MAPPER.readValue(manifestJson, MAP_TYPE);
        } catch (IOException e) {
            throw new IllegalArgumentException("Invalid skill manifest JSON: " + e.getMessage(), e);
        }
    }

    private byte[] readPackage(MultipartFile packageFile) {
        try {
            byte[] bytes = packageFile.getBytes();
            if (bytes.length > maxPackageBytes) {
                throw new IllegalArgumentException(
                        "Skill package exceeds max size of " + maxPackageBytes + " bytes");
            }
            return bytes;
        } catch (IOException e) {
            throw new IllegalArgumentException(

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Include a non-empty JSON manifest part in the multipart request.
  2. At minimum send {} if you want SKILL.md frontmatter to drive all fields — but the version will fall back to a checksum prefix.
  3. Verify the multipart form has both 'manifest' (text) and 'package' (file) parts.

Example fix

# before: only the package part sent
curl -F 'package=@skill.zip' /api/skills/register
# after: include a manifest part
curl -F 'manifest={"name":"foo","version":"1.0.0"}' -F 'package=@skill.zip' /api/skills/register
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: ensure manifest part is present and non-blank
if (manifest == null || manifest.isBlank()) {
    throw new IllegalArgumentException("manifest part is required");
}

Type guard

static boolean manifestPresent(String m) { return m != null && !m.isBlank(); }

Prevention

When it happens

Trigger: POST /api/skills/register with the 'manifest' part missing, empty, or containing only whitespace. Spring binds a missing required @RequestPart to a 400 before this in some configs, but a present-but-blank part reaches here.

Common situations: Client sends the 'package' part but forgets the 'manifest' part; a manifest field that is an empty string in a form builder; content-type negotiation causing the manifest part to deserialize as blank.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/6a90babbefe61f99. Report an issue: GitHub.