{"record":{"id":"a9f45c9c8f368618","repo":"nopSolutions/nopCommerce","slug":"a-theme-with-themedescriptor-systemname-system","errorCode":null,"errorMessage":"A theme with '{themeDescriptor.SystemName}' system name is already defined","messagePattern":"A theme with '(.+?)' system name is already defined","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/Libraries/Nop.Services/Themes/ThemeProvider.cs","lineNumber":64,"sourceCode":"                throw new Exception($\"A theme descriptor '{descriptionFile}' has no system name\");\n\n            _themeDescriptors.TryAdd(themeDescriptor.SystemName, themeDescriptor);\n        }\n    }\n\n    /// <summary>\n    /// Get theme descriptor from the description text\n    /// </summary>\n    /// <param name=\"text\">Description text</param>\n    /// <returns>Theme descriptor</returns>\n    public ThemeDescriptor GetThemeDescriptorFromText(string text)\n    {\n        //get theme description from the JSON file\n        var themeDescriptor = JsonConvert.DeserializeObject<ThemeDescriptor>(text);\n\n        //some validation\n        if (_themeDescriptors.ContainsKey(themeDescriptor.SystemName))\n            throw new Exception($\"A theme with '{themeDescriptor.SystemName}' system name is already defined\");\n\n        return themeDescriptor;\n    }\n\n    /// <summary>\n    /// Get all themes\n    /// </summary>\n    /// <returns>\n    /// A task that represents the asynchronous operation\n    /// The task result contains the list of the theme descriptor\n    /// </returns>\n    public virtual Task<IList<ThemeDescriptor>> GetThemesAsync()\n    {\n        return Task.FromResult<IList<ThemeDescriptor>>(_themeDescriptors.Values.ToList());\n    }\n\n    /// <summary>\n    /// Get a theme by the system name","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/nopSolutions/nopCommerce/blob/64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2/src/Libraries/Nop.Services/Themes/ThemeProvider.cs#L46-L82","documentation":"Thrown by ThemeProvider.GetThemeDescriptorFromText when a freshly parsed ThemeDescriptor's SystemName already exists in the _themeDescriptors cache. GetThemeDescriptorFromText checks ContainsKey against the cache populated by prior calls.","triggerScenarios":"Two theme folders each declare the same SystemName in their themeDescription.json; or the same theme is parsed twice. Because _themeDescriptors is populated by the scan and this method also checks it, a duplicate SystemName triggers the throw.","commonSituations":"Duplicating a theme folder to fork it without renaming SystemName; installing two theme packages that share a SystemName; leftover theme copies from a failed deploy.","solutions":["Give each theme a unique SystemName in its themeDescription.json.","Remove the duplicate theme folder so only one definition remains.","After renaming, clear any theme cache and restart the app."],"exampleFix":"// before: two folders both have\n{ \"SystemName\": \"DefaultClean\" }\n// after: rename the fork\n{ \"SystemName\": \"DefaultCleanFork\" }","handlingStrategy":"validation","validationCode":"var desc = JsonConvert.DeserializeObject<ThemeDescriptor>(text);\nif (existing.ContainsKey(desc.SystemName))\n    // rename SystemName or remove duplicate folder before parse","typeGuard":"static bool IsUniqueSystemName(string json, IDictionary<string,ThemeDescriptor> known)\n    => !known.ContainsKey(JsonConvert.DeserializeObject<ThemeDescriptor>(json).SystemName);","tryCatchPattern":"try { themeProvider.GetThemeDescriptorFromText(text); }\ncatch (Exception ex) when (ex.Message.Contains(\"already defined\"))\n{ logger.Warn($\"Duplicate theme: {ex.Message}\"); }","preventionTips":["Use unique SystemName values per theme.","Remove old theme folders when forking.","Validate uniqueness in a build/deploy check."],"tags":["themes","config","validation","duplicate","startup"],"backgroundTag":null,"analyzedSha":"64bdf2ff08c8b39e65717bcf974fb43dc2ef68f2","analyzedAt":"2026-08-13T21:19:38.062Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}