{"record":{"id":"c15b1340b164b3b0","repo":"gildas-lormeau/SingleFile","slug":"url-already-exists","errorCode":null,"errorMessage":"URL already exists","messagePattern":"URL already exists","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/config.js","lineNumber":678,"sourceCode":"\nasync function getProfile(profileName) {\n\tconst profileKey = PROFILE_NAME_PREFIX + profileName;\n\tconst data = await configStorage.get([profileKey]);\n\treturn data[profileKey];\n}\n\nasync function setProfile(profileName, profileData) {\n\tconst profileKey = PROFILE_NAME_PREFIX + profileName;\n\tawait configStorage.set({ [profileKey]: profileData });\n}\n\nasync function addRule(url, profile, autoSaveProfile) {\n\tif (!url) {\n\t\tthrow new Error(\"URL is empty\");\n\t}\n\tconst rules = await getRules();\n\tif (rules.find(rule => rule.url == url)) {\n\t\tthrow new Error(\"URL already exists\");\n\t}\n\trules.push({\n\t\turl,\n\t\tprofile,\n\t\tautoSaveProfile\n\t});\n\tawait configStorage.set({ rules });\n}\n\nasync function deleteRule(url) {\n\tif (!url) {\n\t\tthrow new Error(\"URL is empty\");\n\t}\n\tconst rules = await getRules();\n\tawait configStorage.set({ rules: rules.filter(rule => rule.url != url) });\n}\n\nasync function deleteRules(profileName) {","sourceCodeStart":660,"sourceCodeEnd":696,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/config.js#L660-L696","documentation":"addRule enforces unique URLs across rules: before pushing the new rule it searches existing rules for one whose url matches exactly (==), and throws 'URL already exists' on a duplicate. Rules are keyed by URL, so two rules for the same URL would be ambiguous.","triggerScenarios":"Calling addRule('https://example.com/*', profile) when a rule with exactly that URL already exists in config storage; or calling addRule twice with the same URL.","commonSituations":"User re-adding a rule that was auto-saved earlier (autoSaveProfile rules); a settings page that doesn't pre-check duplicates before submitting.","solutions":["Before adding, check rules.find(rule => rule.url == url) yourself and update the existing rule (updateRule) instead.","Catch the error and surface 'this URL already has a rule' in the UI.","Normalize/trim the URL before comparison to avoid near-duplicates with different whitespace."],"exampleFix":"// before\nawait addRule(url, profile);\n// after\nconst rules = await getRules();\nif (rules.some(r => r.url == url)) await updateRule(url, url, profile, autoSaveProfile);\nelse await addRule(url, profile, autoSaveProfile);","handlingStrategy":"try-catch","validationCode":"const rules = await getRules();\nif (rules.some(r => r.url == url)) await updateRule(url, url, profile, autoSaveProfile);\nelse await addRule(url, profile, autoSaveProfile);","typeGuard":null,"tryCatchPattern":"try { await addRule(url, profile, asp); } catch (e) { if (e.message === 'URL already exists') notify('This URL already has a rule'); else throw e; }","preventionTips":["Pre-check duplicates in the UI before submit","Disable submit when the URL matches an existing rule","Normalize URLs (trim) before comparisons"],"tags":["duplicate","config","rules"],"backgroundTag":"duplicate-rule","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}