conductor-oss/conductor · error · IllegalArgumentException

Skill package not found: {name}@{version}

Error message

Skill package not found: {name}@{version}

What it means

Thrown by packageBytes when a SkillDetail has a null or blank `packageFileHandleId` — the opaque ID used to read the stored package blob from the SkillPackageStore. The metadata record exists, but the blob it points at is missing, so any operation that needs the actual zip bytes (download, file listing, repackaging) refuses rather than returning garbage.

Source

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

        return matcher.group(2).trim();
    }

    private boolean packageExists(SkillDetail detail) {
        String handle = detail.getPackageFileHandleId();
        if (handle == null || handle.isBlank()) {
            return false;
        }
        try {
            return packageStore.exists(handle);
        } catch (RuntimeException ignored) {
            return false;
        }
    }

    private byte[] packageBytes(SkillDetail detail) {
        String handle = detail.getPackageFileHandleId();
        if (handle == null || handle.isBlank()) {
            throw new IllegalArgumentException(
                    "Skill package not found: " + detail.getName() + "@" + detail.getVersion());
        }
        return packageStore.read(handle);
    }

    private void deletePackage(SkillDetail detail) {
        String handle = detail.getPackageFileHandleId();
        if (handle != null && !handle.isBlank()) {
            try {
                packageStore.delete(handle);
            } catch (IllegalArgumentException ignored) {
                // Legacy records used synthetic handles before the package store existed.
            }
        }
    }

    private String normalizeEntryName(String name) {
        String normalized = name.replace('\\', '/');

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Re-upload the skill package so a fresh blob handle is written and the metadata row's packageFileHandleId is populated.
  2. If this is a legacy record, delete the orphan metadata row and re-publish.
  3. Verify the SkillPackageStore backend is reachable and the DAO write path sets the handle on insert.

Example fix

// before: metadata row with packageFileHandleId = null
// re-publish via the upload API
POST /api/ai/skills/packages  (multipart with the corrected zip)
// after: row carries a real handle id and packageBytes() resolves
Defensive patterns

Strategy: validation

Validate before calling

// Verify a skill has a non-blank package handle before using it.
boolean hasStoredPackage(SkillDetail d) {
    String h = d.getPackageFileHandleId();
    return h != null && !h.isBlank();
}

Type guard

boolean isResolvable(SkillDetail d, SkillPackageStore store) {
    String h = d.getPackageFileHandleId();
    return h != null && !h.isBlank() && store.exists(h);
}

Try / catch

try {
    byte[] bytes = skillRegistry.packageBytes(detail);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Skill package not found")) {
        return notFound(e.getMessage()); // 404, prompt re-upload
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling an API that materializes package bytes (download, list files, read file content) for a skill whose metadata row survived but whose blob was deleted, never written, or migrated incompletely from the legacy synthetic-handle scheme.

Common situations: Partial migration from pre-package-store records; the underlying object store was cleared but the DAO table was not; a delete partially failed and left the metadata row; a manually-inserted test row omitted the handle.

Related errors


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