{"record":{"id":"b9dd99eb19839924","repo":"gildas-lormeau/SingleFile","slug":"new-url-already-exists","errorCode":null,"errorMessage":"New URL already exists","messagePattern":"New URL already exists","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/config.js","lineNumber":711,"sourceCode":"\tawait configStorage.set({ rules: rules.filter(rule => rule.url != url) });\n}\n\nasync function deleteRules(profileName) {\n\tconst rules = await getRules();\n\tawait configStorage.set({ rules: profileName ? rules.filter(rule => rule.autoSaveProfile != profileName && rule.profile != profileName) : [] });\n}\n\nasync function updateRule(url, newURL, profile, autoSaveProfile) {\n\tif (!url || !newURL) {\n\t\tthrow new Error(\"URL is empty\");\n\t}\n\tconst rules = await getRules();\n\tconst urlConfig = rules.find(rule => rule.url == url);\n\tif (!urlConfig) {\n\t\tthrow new Error(\"URL not found\");\n\t}\n\tif (rules.find(rule => rule.url == newURL && rule.url != url)) {\n\t\tthrow new Error(\"New URL already exists\");\n\t}\n\turlConfig.url = newURL;\n\turlConfig.profile = profile;\n\turlConfig.autoSaveProfile = autoSaveProfile;\n\tawait configStorage.set({ rules });\n}\n\nasync function getAuthInfo() {\n\treturn (await configStorage.get()).authInfo;\n}\n\nasync function getDropboxAuthInfo() {\n\treturn (await configStorage.get()).dropboxAuthInfo;\n}\n\nasync function setAuthInfo(authInfo) {\n\tawait configStorage.set({ authInfo });\n}","sourceCodeStart":693,"sourceCodeEnd":729,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/config.js#L693-L729","documentation":"When renaming a rule's URL, updateRule checks that no OTHER rule already uses newURL (rules.find(rule => rule.url == newURL && rule.url != url)) and throws 'New URL already exists' on collision. This preserves the one-rule-per-URL invariant after the rename.","triggerScenarios":"Calling updateRule(urlA, urlB, ...) where urlB is already assigned to a different rule; e.g. editing rule A's URL to the exact value of rule B.","commonSituations":"User renames a rule to a URL that was previously auto-saved by autoSaveProfile; bulk renames applied in an order that collides mid-way.","solutions":["Pre-check with getRules(): if (rules.some(r => r.url == newURL && r.url != url)) show a conflict message before calling.","Delete the conflicting rule first if it should be replaced, then update.","Catch the error and prompt the user to choose a different URL."],"exampleFix":"// before\nawait updateRule(url, newURL, profile);\n// after\nconst rules = await getRules();\nif (rules.some(r => r.url == newURL && r.url != url)) throw new Error('Choose a different URL');\nawait updateRule(url, newURL, profile);","handlingStrategy":"validation","validationCode":"const rules = await getRules();\nif (rules.some(r => r.url == newURL && r.url != url)) throw new Error('New URL already in use');\nawait updateRule(url, newURL, profile, autoSaveProfile);","typeGuard":null,"tryCatchPattern":"try { await updateRule(url, newURL, p, asp); } catch (e) { if (e.message === 'New URL already exists') notify('Another rule uses this URL'); else throw e; }","preventionTips":["Check for collisions in the UI before renaming","Order bulk renames to avoid mid-way conflicts","Prompt users to pick a different URL on collision"],"tags":["duplicate","config","rules"],"backgroundTag":"duplicate-url","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}