JosefNemec/Playnite · error · LocalizedException

LOC.GeneralThemePackageError

Error message

LOC.GeneralThemePackageError

What it means

Thrown by VerifyThemePackage when a theme .pthm package has no theme manifest entry (the file named by PlaynitePaths.ThemeManifestFileName, i.e. theme.yaml). Without the manifest Playnite cannot read the theme's Id, so the package is rejected via LOC.GeneralThemePackageError.

Source

Thrown at source/Playnite/Plugins/ExtensionInstaller.cs:373

                }

                if (zip.Entries.Any(a => a.Name == "Playnite.dll" || a.Name == "Playnite.Common.dll" || a.Name == "Playnite.SDK.dll"))
                {
                    logger.Error($"Extension package is invalid, includes not allowed Playnite dependencies.");
                    throw new LocalizedException(LOC.GeneralExtensionPackageError);
                }
            }
        }

        public static void VerifyThemePackage(string packagePath)
        {
            using (var zip = ZipFile.OpenRead(packagePath))
            {
                var manifestEntry = zip.GetEntry(PlaynitePaths.ThemeManifestFileName);
                if (manifestEntry == null)
                {
                    logger.Error("Theme package is invalid, no manifest found.");
                    throw new LocalizedException(LOC.GeneralThemePackageError);
                }

                using (var logStream = manifestEntry.Open())
                {
                    using (TextReader tr = new StreamReader(logStream))
                    {
                        var manifest = Serialization.FromYaml<ThemeManifest>(tr.ReadToEnd());
                        if (manifest.Id.IsNullOrEmpty())
                        {
                            logger.Error("Theme package is invalid, no extension ID found.");
                            throw new LocalizedException(LOC.GeneralThemePackageError);
                        }

                        if (!Version.TryParse(manifest.Version, out var _))
                        {
                            logger.Error($"Theme package is invalid, version is not in correct format {manifest.Version}.");
                            throw new LocalizedException(LOC.GeneralThemePackageError);
                        }

View on GitHub (pinned to 5911f4e964)

Solutions

  1. Unzip the .pthm and confirm theme.yaml sits at the archive root, not inside a subfolder.
  2. Verify the exact filename and casing match PlaynitePaths.ThemeManifestFileName (theme.yaml).
  3. Re-zip the directory contents (not the parent folder) so entries are top-level.
  4. Re-run VerifyThemePackage before publishing.

Example fix

# before — zip layout
MyTheme/theme.yaml
MyTheme/App.xaml

# after
theme.yaml
App.xaml
Defensive patterns

Strategy: validation

Validate before calling

using (var zip = ZipFile.OpenRead(packagePath))
{
    if (zip.GetEntry(PlaynitePaths.ThemeManifestFileName) == null)
        throw new InvalidOperationException($"Theme package missing {PlaynitePaths.ThemeManifestFileName} at root.");
}

Type guard

static bool ThemeManifestAtRoot(string packagePath)
{
    using (var z = ZipFile.OpenRead(packagePath))
        return z.GetEntry(PlaynitePaths.ThemeManifestFileName) != null;
}

Try / catch

try { ExtensionInstaller.VerifyThemePackage(path); }
catch (LocalizedException) { /* open zip, ensure theme.yaml at archive root */ }

Prevention

When it happens

Trigger: VerifyThemePackage opens the zip, calls zip.GetEntry(PlaynitePaths.ThemeManifestFileName), and gets null at line 370. The manifest file is absent, misnamed, or placed in a subfolder so GetEntry (which is path-sensitive) returns null.

Common situations: Author zipped the project folder rather than its contents, so theme.yaml landed under a nested directory. File named 'theme.yml' instead of 'theme.yaml', or 'Theme.yaml' with wrong casing on a case-sensitive zip. Build script skipped copying the manifest.

Related errors


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