{"record":{"id":"06f0826df71ed366","repo":"gildas-lormeau/SingleFile","slug":"url-not-found","errorCode":null,"errorMessage":"URL not found","messagePattern":"URL not found","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/config.js","lineNumber":708,"sourceCode":"\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) {\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","sourceCodeStart":690,"sourceCodeEnd":726,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/config.js#L690-L726","documentation":"updateRule looks up the rule to edit with rules.find(rule => rule.url == url) and throws 'URL not found' when no rule matches. The original URL acts as the lookup key; if no rule exists with exactly that URL, there is nothing to update.","triggerScenarios":"Calling updateRule with a url that was never added, or one that was already renamed/deleted; passing an untrimmed or differently-cased URL than the stored one.","commonSituations":"Two tabs editing rules concurrently (the other tab deleted/renamed the rule first); stale UI state showing a rule that no longer exists; passing the rule's display URL instead of the stored pattern.","solutions":["Refresh the rule list (getRules) and confirm the URL exists before updating.","Catch the error and reload the rules UI so the user sees current state.","Ensure the url string matches the stored one exactly (trim whitespace, same case)."],"exampleFix":"// before\nawait updateRule(staleUrl, newURL, profile);\n// after\nconst rules = await getRules();\nif (!rules.some(r => r.url == staleUrl)) { await refreshRulesUI(); return; }\nawait updateRule(staleUrl, newURL, profile);","handlingStrategy":"try-catch","validationCode":"const rules = await getRules();\nif (!rules.some(r => r.url == url)) { await refreshRulesUI(); return; }","typeGuard":null,"tryCatchPattern":"try { await updateRule(url, newURL, p, asp); } catch (e) { if (e.message === 'URL not found') { await refreshRulesUI(); notify('Rule no longer exists'); } else throw e; }","preventionTips":["Re-fetch rules before edits to avoid stale state","Compare URLs exactly (trim, case) as stored","Handle concurrent edits across multiple tabs"],"tags":["not-found","config","rules"],"backgroundTag":"rule-not-found","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}