JosefNemec/Playnite · error · Exception
Extension already exists: {outDir}
Error message
Extension already exists: {outDir} What it means
Thrown by Toolbox.Extensions.GenerateScriptExtension when the target output directory (directory + normalized script name) already exists. The generator refuses to overwrite an existing extension to avoid clobbering prior work, so it hard-throws.
Source
Thrown at source/Tools/Playnite.Toolbox/Extensions.cs:77
for (int i = 0; i < input.Length; i++)
{
var chr = input[i];
if (isValidInIdentifier(chr, i == 0))
{
sb.Append(chr);
}
}
return sb.ToString();
}
public static string GenerateScriptExtension(string name, string directory)
{
var normalizedName = ConvertToValidIdentifierName(name);
var outDir = Path.Combine(directory, normalizedName);
if (Directory.Exists(outDir))
{
throw new Exception($"Extension already exists: {outDir}");
}
var templateArchive = Path.Combine(PlaynitePaths.ProgramPath, "Templates", "Extensions", "PowerShellScript.zip"); ;
ZipFile.ExtractToDirectory(templateArchive, outDir);
var pluginId = Guid.NewGuid();
foreach (var filePath in Directory.GetFiles(outDir, "*.*", SearchOption.AllDirectories))
{
var changed = false;
var fileContent = File.ReadAllText(filePath, Encoding.UTF8);
if (fileContent.Contains(nameReplaceMask))
{
fileContent = fileContent.Replace(nameReplaceMask, normalizedName);
changed = true;
}
if (fileContent.Contains(guidReplaceMask))
{
fileContent = fileContent.Replace(guidReplaceMask, pluginId.ToString());
View on GitHub (pinned to 5911f4e964)
Solutions
- Choose a different extension name whose normalized identifier does not collide.
- Move or delete the existing outDir before regenerating.
- Generate into a different parent `directory`.
- If the existing folder is a leftover from a failed run, remove it and retry.
Example fix
// before
Extensions.GenerateScriptExtension("MyAddon", @"C:\dev"); // C:\dev\MyAddon exists -> throws
// after
Extensions.GenerateScriptExtension("MyAddonV2", @"C:\dev"); // new dir
// or: Directory.Delete(@"C:\dev\MyAddon", true); first Defensive patterns
Strategy: validation
Validate before calling
var outDir = Path.Combine(directory, ConvertToValidIdentifierName(name));
if (Directory.Exists(outDir))
throw new InvalidOperationException($"Refusing to overwrite existing extension dir: {outDir}");
// or: pick a unique suffix Type guard
static bool CanScaffoldScriptExtension(string name, string directory) => !Directory.Exists(Path.Combine(directory, ConvertToValidIdentifierName(name)));
Try / catch
try { return Extensions.GenerateScriptExtension(name, directory); }
catch (Exception ex) when (ex.Message.StartsWith("Extension already exists")) { /* prompt user to overwrite or rename */ } Prevention
- Before scaffolding, check whether outDir exists and prompt to overwrite.
- Keep each extension in its own unique parent folder.
- Name extensions distinctly so normalizations don't collide.
When it happens
Trigger: Running `playnite-toolbox new` (or GenerateScriptExtension directly) with a name whose ConvertToValidIdentifierName normalization collides with an existing subdirectory under `directory` (Directory.Exists(outDir) true at line 75).
Common situations: Re-running the scaffolder with the same extension name in the same parent folder. A previous partial run left the directory behind. Two names that normalize to the same identifier (e.g. 'MyAddon' and 'My Addon' both -> 'MyAddon').
Related errors
- Cannot add file to database, file not found.
- Failed to read {path}
- Failed to write to {path}
- Failed to delete {path}
- Source directory does not exist or could not be found: {sour
AI-assisted analysis of JosefNemec/Playnite@5911f4e964 (2026-08-13).
Data as JSON: /api/errors/0abd91ef2959e041.
Report an issue: GitHub.