{"record":{"id":"32a4d1e091d5fa88","repo":"gildas-lormeau/SingleFile","slug":"default-settings-cannot-be-deleted","errorCode":null,"errorMessage":"Default settings cannot be deleted","messagePattern":"Default settings cannot be deleted","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/config.js","lineNumber":631,"sourceCode":"\t\t}\n\t\tif (rule.autoSaveProfile == oldProfileName) {\n\t\t\trule.autoSaveProfile = profileName;\n\t\t}\n\t});\n\tconst profile = await getProfile(oldProfileName);\n\tawait configStorage.remove([PROFILE_NAME_PREFIX + oldProfileName]);\n\tawait configStorage.set({ [PROFILE_NAME_PREFIX + profileName]: profile, rules });\n}\n\nasync function deleteProfile(profileName) {\n\tconst profileNames = await getProfileNames();\n\tconst allTabsData = await tabsData.get();\n\tconst rules = await getRules();\n\tif (!profileNames.includes(profileName)) {\n\t\tthrow new Error(\"Profile not found\");\n\t}\n\tif (profileName == DEFAULT_PROFILE_NAME) {\n\t\tthrow new Error(\"Default settings cannot be deleted\");\n\t}\n\tif (allTabsData.profileName == profileName) {\n\t\tdelete allTabsData.profileName;\n\t\tawait tabsData.set(allTabsData);\n\t}\n\trules.forEach(rule => {\n\t\tif (rule.profile == profileName) {\n\t\t\trule.profile = DEFAULT_PROFILE_NAME;\n\t\t}\n\t\tif (rule.autoSaveProfile == profileName) {\n\t\t\trule.autoSaveProfile = DEFAULT_PROFILE_NAME;\n\t\t}\n\t});\n\tconfigStorage.remove([PROFILE_NAME_PREFIX + profileName]);\n\tawait configStorage.set({ rules });\n}\n\nasync function getRules() {","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/config.js#L613-L649","documentation":"deleteProfile refuses to delete the built-in default profile (DEFAULT_PROFILE_NAME). The default profile is a permanent baseline configuration ('Default settings') used whenever no other profile applies, so the library intentionally makes it undeletable. Any deleteProfile call targeting it throws this error before any storage mutation occurs.","triggerScenarios":"Calling deleteProfile(profileName) from the extension message handler (onMessage) with profileName equal to DEFAULT_PROFILE_NAME; e.g. a UI 'delete' action on the default settings entry.","commonSituations":"Rendering delete buttons for every profile in a settings page including the default one; programmatic cleanup that iterates all getProfileNames() results and deletes each without filtering out the default.","solutions":["Guard the call: if (profileName === DEFAULT_PROFILE_NAME) skip or disable the delete action in the UI.","Filter the default profile out of bulk-delete loops: for (const name of names.filter(n => n !== DEFAULT_PROFILE_NAME)) await deleteProfile(name);","If the intent is to restore defaults, call resetProfile(DEFAULT_PROFILE_NAME) instead of deleting."],"exampleFix":"// before\nfor (const name of await getProfileNames()) await deleteProfile(name);\n// after\nfor (const name of (await getProfileNames()).filter(n => n !== DEFAULT_PROFILE_NAME)) await deleteProfile(name);","handlingStrategy":"validation","validationCode":"if (profileName === DEFAULT_PROFILE_NAME) return; // skip delete\nawait deleteProfile(profileName);","typeGuard":"const isDefaultProfile = (name) => typeof name === 'string' && name === DEFAULT_PROFILE_NAME;","tryCatchPattern":"try { await deleteProfile(name); } catch (e) { if (e.message === 'Default settings cannot be deleted') { /* disable UI control */ } else throw e; }","preventionTips":["Never render a delete control for the default profile","Filter DEFAULT_PROFILE_NAME out of bulk operations","Use resetProfile for 'restore defaults' flows"],"tags":["config","profile","protected-resource"],"backgroundTag":"default-profile-not-deletable","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}