{"record":{"id":"2739c0984503ef54","repo":"HeyPuter/puter","slug":"forbidden-2739c0","errorCode":"forbidden","errorMessage":"Cannot delete a protected subdomain","messagePattern":"Cannot delete a protected subdomain","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/controllers/hosting/HostingController.js","lineNumber":85,"sourceCode":"                const { site_uuid } = req.body ?? {};\n                if (!site_uuid || typeof site_uuid !== 'string') {\n                    throw new HttpError(400, 'Missing or invalid `site_uuid`', {\n                        legacyCode: 'bad_request',\n                    });\n                }\n\n                const row = await this.subdomainStore.getByUuid(site_uuid, {\n                    userId: req.actor.user.id,\n                });\n                if (!row) {\n                    throw new HttpError(\n                        404,\n                        'Site not found or not owned by you',\n                        { legacyCode: 'not_found' },\n                    );\n                }\n                if (row.protected) {\n                    throw new HttpError(\n                        403,\n                        'Cannot delete a protected subdomain',\n                        { legacyCode: 'forbidden' },\n                    );\n                }\n\n                await this.subdomainStore.deleteByUuid(site_uuid, {\n                    userId: req.actor.user.id,\n                });\n\n                res.json({});\n            },\n        );\n    }\n\n    onServerStart() {}\n    onServerPrepareShutdown() {}\n    onServerShutdown() {}","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/hosting/HostingController.js#L67-L103","documentation":"The site row exists and is owned by the caller, but its `protected` flag is set, so the controller refuses deletion with HTTP 403. Protected subdomains are reserved system sites that must not be removed through the public delete endpoint. This is a deliberate guard, not a bug.","triggerScenarios":"Calling `POST /delete-site` with the UUID of a protected subdomain (e.g., a default/system-hosted site). The store returns the row, but `row.protected` is truthy.","commonSituations":"Trying to clean up a default site created during provisioning; an admin marked a site protected and a user attempts deletion; automated cleanup scripts that iterate all sites without checking the flag.","solutions":["Do not attempt to delete protected subdomains via the public API — they are intentionally locked.","If protection is no longer needed, unprotect the site through the admin/DB layer first, then retry.","Filter protected sites out of any bulk-delete or cleanup script.","Surface a clear message to the user that this site cannot be removed."],"exampleFix":"// before — delete without checking\nawait api.call('delete-site', { site_uuid: site.uuid });\n\n// after — skip protected sites in bulk operations\nif (site.protected) {\n  console.log(`Skipping protected site: ${site.subdomain}`);\n  continue;\n}\nawait api.call('delete-site', { site_uuid: site.uuid });","handlingStrategy":"validation","validationCode":"// Check the protected flag from the site list before attempting delete\nconst sites = await api.call('hosting/sites');\nconst site = sites.find(s => s.uuid === site_uuid);\nif (site?.protected) {\n  alert('This site is protected and cannot be deleted.');\n  return;\n}\nawait api.call('delete-site', { site_uuid });","typeGuard":"/** @typedef {{ uuid: string, protected?: boolean }} SiteRow */\n/** @param {SiteRow} s @returns {boolean} */\nfunction isDeletable(s) {\n  return !s.protected;\n}","tryCatchPattern":"try {\n  await api.call('delete-site', { site_uuid });\n} catch (e) {\n  if (e.code === 'forbidden') {\n    console.error('This site is protected and cannot be deleted.');\n  } else throw e;\n}","preventionTips":["Fetch the `protected` flag from the site list and disable/hide delete buttons for protected sites.","Filter protected sites out of bulk-delete scripts.","Communicate to users why certain sites cannot be removed."],"tags":["hosting","authorization","forbidden","http-403","protected-resource"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}