microsoft/aspire · error · InvalidOperationException
Skill ' ' does not define installable files.
Error message
Skill '{skill.Name}' does not define installable files. What it means
GetSkillFilesAsync ends with a terminal throw for skills that match none of the supported source kinds (e.g. not an Aspire skills bundle or another file-providing source) yet carry no installable files. The library throws because it cannot produce the file set the agent-init install step requires for this skill.
Solutions
- Add installable file definitions to the skill so it maps to a supported file-providing source kind
- Exclude the file-less skill from the file-install path (it may only need registration, not file installation)
- Verify the skill's manifest declares the correct SourceKind
Example fix
// before
var files = await GetSkillFilesAsync(skill, aspireSkillsBundle, cancellationToken);
// after
if (skill.SourceKind is not (SkillSourceKind.AspireSkillsBundle or SkillSourceKind.LocalFiles))
{
continue; // file-less skill: register without installing files
}
var files = await GetSkillFilesAsync(skill, aspireSkillsBundle, cancellationToken); Defensive patterns
Strategy: validation
Validate before calling
if (!skillHasInstallableFiles(skill))
{
continue; // file-less skill: skip the file-install path
} Type guard
var hasFiles = skill.SourceKind is SkillSourceKind.AspireSkillsBundle or SkillSourceKind.LocalFiles;
Try / catch
try
{
files = await GetSkillFilesAsync(skill, bundle, ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("does not define installable files"))
{
logger.LogInformation("Skill {Skill} has no files; registering only", skill.Name);
} Prevention
- Only pass file-providing skills to GetSkillFilesAsync
- Check the skill manifest for file definitions before install
- Register instruction-only skills through a separate path
When it happens
Trigger: Invoking GetSkillFilesAsync with a skill whose SourceKind is a kind that does not implement GetSkillFilesAsync and that defines no installable file entries — e.g. a metadata-only or inline/documented skill with no files.
Common situations: A custom or user-defined skill in the agent-init skill configuration that only provides instructions (no files), but is processed by the file-install path; misconfigured skill manifest missing its file definitions.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Aspire skills bundle contains an empty relative path.
- Aspire skills bundle skill
- Aspire skills bundle was not resolved for skill
- Polyglot skeleton not yet supported for language
- A circular lifetime reference was detected for resource
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/d2d52435c45ce318.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Cli/Commands/AgentInitCommand.cs:771
private static async Task<IReadOnlyList<SkillAssetFile>> GetSkillFilesAsync(SkillDefinition skill, AspireSkillsBundle? aspireSkillsBundle, CancellationToken cancellationToken)
{
if (skill.SkillContent is not null)
{
return [new SkillAssetFile("SKILL.md", skill.SkillContent)];
}
if (skill.SourceKind is SkillSourceKind.AspireSkillsBundle)
{
if (aspireSkillsBundle is null)
{
throw new InvalidOperationException($"Aspire skills bundle was not resolved for skill '{skill.Name}'.");
}
return await aspireSkillsBundle.GetSkillFilesAsync(skill, cancellationToken);
}
throw new InvalidOperationException($"Skill '{skill.Name}' does not define installable files.");
}
private sealed record InstalledSkillSummaryItem(string SkillName, string DisplayLocation);
private readonly record struct SkillInstallResult(bool Succeeded, InstalledSkillSummaryItem? UpdatedSkill);
}
internal readonly record struct AgentInitExecutionResult(
int ExitCode,
IReadOnlyList<SkillLocation> SelectedLocations,
IReadOnlyList<SkillDefinition> SelectedSkills);
View on GitHub (pinned to 25830f84bd)