JosefNemec/Playnite · error · Exception
Cannot package extension, ID is missing!
Error message
Cannot package extension, ID is missing!
What it means
Thrown by Extensions.PackageExtension after the manifest is loaded but its Id field is null or empty. ExtensionInstaller.GetExtensionManifest(manifestPath) deserializes extension.yaml into an ExtensionManifest; if the Id property is absent or blank in the YAML, packaging stops because the packed filename (Id_Version.pext) and add-on identity both depend on it. Note this runs before VerifyManifest, so a bad Version alone will not reach here.
Source
Thrown at source/Tools/Playnite.Toolbox/Extensions.cs:195
File.Move(Path.Combine(outDir, baseProjectName + ".sln"), outSolutionFile);
FileSystem.ReplaceStringInFile(outProjectFile, baseProjectName, normalizedName);
FileSystem.ReplaceStringInFile(outSolutionFile, baseProjectName, normalizedName);
return outDir;
}
public static string PackageExtension(string extDirectory, string targetPath)
{
var dirInfo = new DirectoryInfo(extDirectory);
var manifestPath = Path.Combine(extDirectory, PlaynitePaths.ExtensionManifestFileName);
if (!File.Exists(manifestPath))
{
throw new Exception($"Manifest file ({PlaynitePaths.ExtensionManifestFileName}) not found!");
}
var extInfo = ExtensionInstaller.GetExtensionManifest(manifestPath);
if (extInfo.Id.IsNullOrEmpty())
{
throw new Exception("Cannot package extension, ID is missing!");
}
extInfo.VerifyManifest();
var packedPath = Path.Combine(targetPath, $"{Common.Paths.GetSafePathName(extInfo.Id).Replace(' ', '_')}_{extInfo.Version.ToString().Replace(".", "_")}{PlaynitePaths.PackedExtensionFileExtention}");
FileSystem.PrepareSaveFile(packedPath);
var ignoreFiles = File.ReadAllLines(Paths.ExtFileIgnoreListPath);
using (var zipStream = new FileStream(packedPath, FileMode.Create))
{
using (var zipFile = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
foreach (var file in Directory.GetFiles(extDirectory, "*.*", SearchOption.AllDirectories))
{
var subName = file.Replace(extDirectory, "").TrimStart(Path.DirectorySeparatorChar);
if (ignoreFiles.ContainsString(subName, StringComparison.OrdinalIgnoreCase))
{
continue;
View on GitHub (pinned to 5911f4e964)
Solutions
- Open extension.yaml and confirm a top-level `Id: <unique_identifier>` line exists with correct two-space YAML indentation and no surrounding quotes that collapse to empty.
- Use the exact casing `Id` (PascalCase) — the manifest model property is `Id`, and YamlDotNet is case-sensitive here.
- Run a quick parse check: deserialize via ExtensionInstaller.GetExtensionManifest and assert `!string.IsNullOrEmpty(manifest.Id)` before invoking PackageExtension.
- Ensure Id is non-empty after any GenerateScriptExtension/GeneratePluginExtension run that may have left a placeholder.
Example fix
// before Id: Name: My Plugin // after Id: MyUniquePlugin_7c3f Name: My Plugin
Defensive patterns
Strategy: validation
Validate before calling
var man = ExtensionInstaller.GetExtensionManifest(manifestPath);
if (man.Id.IsNullOrEmpty())
throw new InvalidOperationException($"extension.yaml at {manifestPath} has no Id"); Prevention
- Keep the exact key name `Id` (PascalCase) in extension.yaml.
- After scaffolding or editing the manifest, deserialize and assert a non-empty Id before packaging.
- Lint YAML indentation (spaces, not tabs) to ensure Id binds at the top level.
When it happens
Trigger: extension.yaml exists and parses, but the top-level `Id:` key is missing, commented out, or set to an empty string. Also occurs if YAML indentation put Id under the wrong node so the deserializer never binds it.
Common situations: Authors copy a template and forget to fill in Id; an editor auto-removed a perceived-duplicate key; YAML uses a tab where a space is required, silently mis-indenting Id; Id is spelled `id:` or `ID:` and the YamlDotNet binding is case-sensitive.
Related errors
- Cannot package theme, ID is missing!
- LOC.GeneralThemePackageError
- Manifest file ({PlaynitePaths.ExtensionManifestFileName}) no
- LOC.GeneralExtensionPackageError
- Manifest file ({PlaynitePaths.ThemeManifestFileName}) not fo
AI-assisted analysis of JosefNemec/Playnite@5911f4e964 (2026-08-13).
Data as JSON: /api/errors/5fa29c468664eca4.
Report an issue: GitHub.