JosefNemec/Playnite · error · Exception

Cannot package theme, ID is missing!

Error message

Cannot package theme, ID is missing!

What it means

Thrown by Themes.PackageTheme after GetThemeManifest succeeds but the Id field is null or empty. The theme's packed filename (Id_Version.pthm) and identity require Id, so packaging halts. This check precedes VerifyManifest and the API-version comparison.

Source

Thrown at source/Tools/Playnite.Toolbox/Themes.cs:183

            else
            {
                return FileSystem.GetMD5(file1) == FileSystem.GetMD5(file2);
            }
        }

        public static string PackageTheme(string themeDirectory, string targetPath, ApplicationMode mode)
        {
            var dirInfo = new DirectoryInfo(themeDirectory);
            var manifestPath = Path.Combine(themeDirectory, PlaynitePaths.ThemeManifestFileName);
            if (!File.Exists(manifestPath))
            {
                throw new Exception($"Manifest file ({PlaynitePaths.ThemeManifestFileName}) not found!");
            }

            var extInfo = ExtensionInstaller.GetThemeManifest(manifestPath);
            if (extInfo.Id.IsNullOrEmpty())
            {
                throw new Exception("Cannot package theme, ID is missing!");
            }

            extInfo.VerifyManifest();

            var apiVer = extInfo.Mode == ApplicationMode.Desktop ? ThemeManager.DesktopApiVersion : ThemeManager.FullscreenApiVersion;
            var themeApiVer = Version.Parse(extInfo.ThemeApiVersion);
            if (themeApiVer > apiVer)
            {
                throw new Exception($"Cannot package theme. Unsupported API version detected: {themeApiVer}");
            }
            else if (themeApiVer != apiVer)
            {
                logger.Warn("Selected theme has not been updated to the latest supported API version. Please consider updating the theme!");
                logger.Warn("https://github.com/JosefNemec/Playnite/issues/1259");
            }

            var defaultThemeDir = Path.Combine(Paths.GetThemesPath(mode), "Default");
            targetPath = Path.Combine(targetPath, $"{Common.Paths.GetSafePathName(extInfo.Id).Replace(' ', '_')}_{extInfo.Version.ToString().Replace(".", "_")}{PlaynitePaths.PackedThemeFileExtention}");

View on GitHub (pinned to 5911f4e964)

Solutions

  1. Add a non-empty top-level `Id: <unique_theme_id>` to theme.yaml with correct two-space indentation.
  2. Match the exact casing `Id` (the manifest model property name).
  3. Pre-validate by deserializing via ExtensionInstaller.GetThemeManifest and asserting `!string.IsNullOrEmpty(man.Id)`.
  4. Give the theme a unique Id to avoid collisions with the Default or other installed themes.

Example fix

// before
Id:
Name: My Theme

// after
Id: MyTheme_a1b2
Name: My Theme
Defensive patterns

Strategy: validation

Validate before calling

var man = ExtensionInstaller.GetThemeManifest(manifestPath);
if (man.Id.IsNullOrEmpty())
    throw new InvalidOperationException($"theme.yaml at {manifestPath} has no Id");

Prevention

When it happens

Trigger: theme.yaml parses but its top-level `Id:` is missing, blank, or mis-indented so YamlDotNet does not bind it. YamlDotNet binding is case-sensitive, so `id:` or `ID:` also leaves the property empty.

Common situations: Copying a Default theme and forgetting to set a unique Id; an editor stripping perceived-blank lines; tabs instead of spaces breaking YAML structure; placeholder Id left empty from the template.

Related errors


AI-assisted analysis of JosefNemec/Playnite@5911f4e964 (2026-08-13). Data as JSON: /api/errors/a1f78591529318f1. Report an issue: GitHub.