{"record":{"id":"b3ab3f1dd7b3598b","repo":"infiniflow/ragflow","slug":"failed-to-get-skill-folder-id","errorCode":null,"errorMessage":"Failed to get skill folder ID","messagePattern":"Failed to get skill folder ID","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/pages/skills/hooks.ts","lineNumber":827,"sourceCode":"          } else {\n            // Create skill folder\n            const folderRes = await fileManagerService.createFolder({\n              name: skillNameNormalized,\n              type: 'folder',\n              parent_id: spaceFolderId,\n            });\n\n            if (folderRes.data.code !== 0) {\n              throw new Error('Failed to create skill folder');\n            }\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","sourceCodeStart":809,"sourceCodeEnd":845,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/web/src/pages/skills/hooks.ts#L809-L845","documentation":"Thrown in web/src/pages/skills/hooks.ts:827 when the skill folder id is still falsy after both branches (reuse-existing and create-new) ran. It is a consistency guard: either the created folder response omitted data.id, or an assignment path silently produced undefined (e.g. existingSkill found but with no id, or a branch was skipped).","triggerScenarios":"createFolder returns code 0 but data.id is missing (backend response shape change); existing skill folder matched with an undefined id field; a code path assigns skillFolderId from a nested optional that is absent.","commonSituations":"Backend API response schema drift after an upgrade. Partial/trimmed backend response under proxy buffering. Tests stubbing createFolder without an id.","solutions":["Log the raw createFolder/listFile responses to see which id field is missing","Guard each branch: throw immediately if existingSkill.id or folderRes.data.data?.id is falsy, with branch-specific messages","Align the response typing (data.data.id) with the current backend contract","Retry folder creation once if the response was code 0 but id-less"],"exampleFix":"// before\nif (!skillFolderId) throw new Error('Failed to get skill folder ID');\n\n// after\nif (!skillFolderId) {\n  throw new Error(\n    'Failed to get skill folder ID (created=' +\n      String(createdFolder) +\n      ', reused=' +\n      String(reusedFolder) +\n      ')',\n  );\n}","handlingStrategy":"validation","validationCode":"const folderIdFrom = (res: any): string | null =>\n  res?.data?.data?.id ?? res?.data?.id ?? null;","typeGuard":"const isNonEmptyId = (v: unknown): v is string =>\n  typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":null,"preventionTips":["Check the id at each assignment site and fail with branch-specific context","Keep the createFolder response type in sync with the backend schema"],"tags":["skills","file-manager","upload","data-integrity"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}