{"record":{"id":"ceb34086badde818","repo":"infiniflow/ragflow","slug":"failed-to-get-version-folder-id","errorCode":null,"errorMessage":"Failed to get version folder ID","messagePattern":"Failed to get version folder ID","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/pages/skills/hooks.ts","lineNumber":843,"sourceCode":"        }\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();\n            formData.append('parent_id', parentId);\n            formData.append('file', file);\n            await fileManagerService.uploadFile(formData);\n            return;\n          }\n","sourceCodeStart":825,"sourceCodeEnd":861,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/web/src/pages/skills/hooks.ts#L825-L861","documentation":"Thrown in web/src/pages/skills/hooks.ts:843 when the version-folder creation call returned code 0 but data.id is missing (versionFolderId falsy). It is a response-shape guard: the backend claims success yet the id needed to place files is absent, so continuing would upload files to an unknown parent.","triggerScenarios":"Backend createFolder response omits data.id after an API change; proxy truncates the JSON; a mocked/stubbed service in tests returns {code: 0} only; race where the created folder is immediately deleted and a follow-up fetch returns no id.","commonSituations":"Frontend/backend version skew after upgrading only one side. Test doubles not matching the real contract. Unusual gateway buffering stripping parts of the body.","solutions":["Log the full versionRes payload to confirm which field carries the id in the current API","Update the typing of createFolder's response to match the backend (e.g. data.id vs data.data.id)","If id is genuinely absent, re-list the parent and match by version name to recover the id","Fail fast with a specific message naming the version that failed"],"exampleFix":"// before\nconst versionFolderId = versionRes.data.data?.id;\nif (!versionFolderId)\n  throw new Error('Failed to get version folder ID');\n\n// after\nlet versionFolderId = versionRes.data.data?.id;\nif (!versionFolderId) {\n  const { data: relist } = await fileManagerService.listFile({\n    parent_id: skillFolderId,\n  });\n  versionFolderId = (relist.data?.files || []).find(\n    (f: any) => f.type === 'folder' && f.name === version,\n  )?.id;\n}\nif (!versionFolderId)\n  throw new Error(`Failed to get version folder ID for ${version}`);","handlingStrategy":"fallback","validationCode":"const versionIdOrRecover = async (res: any, skillFolderId: string, version: string) => {\n  const id = res?.data?.data?.id;\n  if (id) return id;\n  const list = await fileManagerService.listFile({ parent_id: skillFolderId });\n  return (list.data?.files || []).find((f) => f.name === version)?.id ?? null;\n};","typeGuard":"const isFolderId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":null,"preventionTips":["Type createFolder's response accurately and log the raw payload when the id is missing","Recover ids by name-matching a re-list instead of aborting"],"tags":["skills","file-manager","upload","data-integrity"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}