{"record":{"id":"fc867f400e4c01e3","repo":"HeyPuter/puter","slug":"forbidden-fc867f","errorCode":"forbidden","errorMessage":"Cannot create at root","messagePattern":"Cannot create at root","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"error","filePath":"src/backend/controllers/webdav/WebDAVController.ts","lineNumber":479,"sourceCode":"        res.status(207)\n            .set({ 'Content-Type': 'application/xml; charset=utf-8' })\n            .send(\n                `<?xml version=\"1.0\" encoding=\"utf-8\"?>\\n<D:multistatus xmlns:D=\"DAV:\"><D:response><D:href>${escapeXml(encodeURI(davPath))}</D:href><D:propstat><D:prop/><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response></D:multistatus>`,\n            );\n    }\n\n    // -- MKCOL -------------------------------------------------------\n\n    async #mkcol(\n        req: Request,\n        res: Response,\n        actor: Actor,\n        davPath: string,\n        redis: unknown,\n        lockToken: string | null,\n    ): Promise<void> {\n        if (davPath === '/')\n            throw new HttpError(403, 'Cannot create at root', {\n                legacyCode: 'forbidden',\n            });\n        if (\n            req.headers['content-length'] &&\n            Number(req.headers['content-length']) > 0\n        ) {\n            throw new HttpError(415, 'MKCOL must not have a body', {\n                legacyCode: 'bad_request',\n            });\n        }\n        if (\n            !(await hasWritePermission(\n                redis as import('ioredis').Cluster,\n                davPath,\n                lockToken,\n            ))\n        ) {\n            throw new HttpError(423, 'Locked', { legacyCode: 'conflict' });","sourceCodeStart":461,"sourceCodeEnd":497,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/webdav/WebDAVController.ts#L461-L497","documentation":"Returned (HTTP 403, legacy code forbidden) by WebDAVController.#mkcol when davPath is '/' — i.e. MKCOL against the filesystem root. The root collection already exists and cannot be created; the server refuses rather than returning a generic 'already exists'.","triggerScenarios":"A WebDAV MKCOL request whose target is the mount root (the user's top-level directory). A misconfigured client that resolves all paths against '/' and issues MKCOL '/' on connect.","commonSituations":"WebDAV client boot sequence that creates a base folder and the base folder resolves to root; incorrect base-path configuration so the effective path collapses to '/'.","solutions":["MKCOL a named subfolder, e.g. /MyFolder, never '/'.","Fix the client's base-path so requests target a child collection.","Treat root as always-present; skip the MKCOL if the target is root."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function assertMkcolTarget(p){ if (p === '/' || p === '') throw new Error('cannot MKCOL root; target a named subfolder'); }","typeGuard":null,"tryCatchPattern":"try { await davMkcol(path); }\ncatch (e) { if (e.status === 403 && /root/i.test(e.message)) { path = path + 'Home/'; await davMkcol(path); } else throw e; }","preventionTips":["Never MKCOL '/'.","Configure the client base-path to a named folder.","Treat root as pre-existing."],"tags":["webdav","mkcol","forbidden","filesystem","root"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}