{"record":{"id":"106f2c687486a35b","repo":"infiniflow/ragflow","slug":"failed-to-create-directory-dirname","errorCode":null,"errorMessage":"Failed to create directory: ${dirName}","messagePattern":"Failed to create directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/pages/skills/hooks.ts","lineNumber":891,"sourceCode":"              throw new Error(`Failed to list directory: ${dirName}`);\n            }\n\n            const existingDir = listData.data?.files?.find(\n              (f: any) => f.name === dirName && f.type === 'folder',\n            );\n\n            if (existingDir) {\n              currentParentId = existingDir.id;\n            } else {\n              // Create subdirectory\n              const createRes = await fileManagerService.createFolder({\n                name: dirName,\n                type: 'folder',\n                parent_id: currentParentId,\n              });\n\n              if (createRes.data.code !== 0) {\n                throw new Error(`Failed to create directory: ${dirName}`);\n              }\n\n              currentParentId = createRes.data.data?.id;\n            }\n          }\n\n          // Upload file to the final directory\n          const formData = new FormData();\n          formData.append('parent_id', currentParentId);\n          formData.append('file', file);\n          await fileManagerService.uploadFile(formData);\n        };\n\n        // Upload all files sequentially to avoid race conditions\n        for (const file of filteredFiles) {\n          await uploadFileWithStructure(file, versionFolderId);\n        }\n","sourceCodeStart":873,"sourceCodeEnd":909,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/web/src/pages/skills/hooks.ts#L873-L909","documentation":"Thrown in web/src/pages/skills/hooks.ts:891 when creating a subdirectory of the uploaded skill's directory tree fails (createFolder code !== 0). The recursive walker creates missing intermediate folders (like src/utils) before uploading the file into the deepest one. Most common cause is a name collision — the folder was created between the list-check and the create — or an invalid parent after a concurrent modification.","triggerScenarios":"Parallel uploads of two files sharing a subdirectory: both see it missing, the second create loses the race; parent folder deleted mid-walk; dirName contains characters rejected by the backend (leading dot, slash); permission loss on the parent.","commonSituations":"Multi-file upload where Promise.all runs uploadFileWithStructure concurrently for files in the same new subfolder. Uploading OS junk paths (.DS_Store handled elsewhere, but similar hidden dirs). Space shared with another editor.","solutions":["Serialize folder creation per directory chain (or create all folders up-front) to eliminate the race","On failure, re-list and reuse the folder if it now exists (someone else created it)","Sanitize dirName (strip dots/slashes) before calling createFolder","Surface createRes.data.message in the thrown error"],"exampleFix":"// before\nconst createRes = await fileManagerService.createFolder({\n  name: dirName,\n  type: 'folder',\n  parent_id: currentParentId,\n});\nif (createRes.data.code !== 0) {\n  throw new Error(`Failed to create directory: ${dirName}`);\n}\n\ncurrentParentId = createRes.data.data?.id;\n\n// after\nconst createRes = await fileManagerService.createFolder({\n  name: dirName,\n  type: 'folder',\n  parent_id: currentParentId,\n});\nif (createRes.data.code !== 0) {\n  const { data: recheck } = await fileManagerService.listFile({\n    parent_id: currentParentId,\n  });\n  const nowExists = (recheck.data?.files || []).find(\n    (f: any) => f.type === 'folder' && f.name === dirName,\n  );\n  if (!nowExists) {\n    throw new Error(\n      `Failed to create directory: ${dirName} (${createRes.data.message})`,\n    );\n  }\n  currentParentId = nowExists.id;\n} else {\n  currentParentId = createRes.data.data?.id;\n}","handlingStrategy":"fallback","validationCode":"const sanitizedDirName = (name: string) =>\n  name.replace(/[/\\\\]/g, '').replace(/^\\.+/, '').trim();","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fileManagerService.createFolder({...});\n  if (res.data.code !== 0) throw new Error(res.data.message);\n} catch (e) {\n  if (/exists/i.test(e.message)) { /* re-list, reuse id */ } else throw e;\n}","preventionTips":["Create the directory chain once (serialized) before uploading files into it, removing the race","Sanitize directory names derived from webkitRelativePath"],"tags":["skills","file-manager","upload","race-condition"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}