{"record":{"id":"56a4e9d4f2c34cc3","repo":"infiniflow/ragflow","slug":"failed-to-create-version-folder","errorCode":null,"errorMessage":"Failed to create version folder","messagePattern":"Failed to create version folder","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/pages/skills/hooks.ts","lineNumber":837,"sourceCode":"            }\n\n            skillFolderId = folderRes.data.data?.id;\n          }\n        } else {\n          throw new Error('Failed to list skills folder');\n        }\n\n        if (!skillFolderId) throw new Error('Failed to get skill folder ID');\n\n        // Create version folder\n        const versionRes = await fileManagerService.createFolder({\n          name: version,\n          type: 'folder',\n          parent_id: skillFolderId,\n        });\n\n        if (versionRes.data.code !== 0) {\n          throw new Error('Failed to create version folder');\n        }\n\n        const versionFolderId = versionRes.data.data?.id;\n\n        if (!versionFolderId)\n          throw new Error('Failed to get version folder ID');\n\n        // Upload files recursively to preserve directory structure\n        const uploadFileWithStructure = async (\n          file: File,\n          parentId: string,\n        ) => {\n          const relativePath = (file as any).webkitRelativePath || file.name;\n          const pathParts = relativePath.split('/');\n\n          // If file is in root directory (no subdirectories)\n          if (pathParts.length === 1) {\n            const formData = new FormData();","sourceCodeStart":819,"sourceCodeEnd":855,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/web/src/pages/skills/hooks.ts#L819-L855","documentation":"Thrown in web/src/pages/skills/hooks.ts:837 when createFolder for the skill's version subfolder (e.g. '1.0.0' under the skill folder) returns code !== 0. Uploads are organized as space/skill/version/, so the version folder must exist before files land. Typical causes: the version folder already exists (re-upload of the same version) or the skill folder id became invalid.","triggerScenarios":"Re-uploading the same skill at the same version: the version folder already exists and the backend rejects the duplicate; skillFolderId stale after a concurrent delete; invalid version string (empty or with characters the backend rejects) used as folder name.","commonSituations":"Uploading an updated skill without bumping the version. Version input left blank, producing an odd folder name. Two uploads racing on the same skill+version.","solutions":["Before creating, list skillFolderId and reuse an existing folder whose name matches the version","Require a non-empty semver-like version in the form and disable upload otherwise","Surface createFolder's response message in the error","Bump the version number when re-uploading a modified skill"],"exampleFix":"// before\nconst versionRes = await fileManagerService.createFolder({\n  name: version,\n  type: 'folder',\n  parent_id: skillFolderId,\n});\nif (versionRes.data.code !== 0) {\n  throw new Error('Failed to create version folder');\n}\n\n// after\nconst { data: skillContents } = await fileManagerService.listFile({\n  parent_id: skillFolderId,\n});\nconst existingVersion = (skillContents.data?.files || []).find(\n  (f: any) => f.type === 'folder' && f.name === version,\n);\nconst versionFolderId =\n  existingVersion?.id ??\n  (\n    await fileManagerService.createFolder({\n      name: version,\n      type: 'folder',\n      parent_id: skillFolderId,\n    })\n  ).data.data?.id;\nif (!versionFolderId) {\n  throw new Error('Failed to create version folder');\n}","handlingStrategy":"validation","validationCode":"const isValidVersion = (v: string) => /^\\d+\\.\\d+\\.\\d+/.test(v.trim());\nconst versionFolderExists = async (skillFolderId: string, version: string) =>\n  (await fileManagerService.listFile({ parent_id: skillFolderId }))\n    .data.data?.files?.some((f) => f.type === 'folder' && f.name === version) ?? false;","typeGuard":"const isSemver = (v: unknown): v is string =>\n  typeof v === 'string' && /^\\d+\\.\\d+\\.\\d+/.test(v);","tryCatchPattern":null,"preventionTips":["Require a semver version in the upload form","Reuse an existing version folder on re-upload instead of creating a duplicate"],"tags":["skills","file-manager","upload","versioning"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}