{"record":{"id":"6eabb9752555b627","repo":"infiniflow/ragflow","slug":"space-id-is-required","errorCode":null,"errorMessage":"Space ID is required","messagePattern":"Space ID is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/pages/skills/hooks.ts","lineNumber":1005,"sourceCode":"        return false;\n      } finally {\n        setLoading(false);\n      }\n    },\n    [t, fetchSkills, ensureSkillSpaceFolder],\n  );\n\n  // Delete a skill\n  const deleteSkill = useCallback(\n    async (\n      skillId: string,\n      _skillName?: string,\n      spaceId?: string,\n      spaceName?: string,\n      folderId?: string,\n    ): Promise<boolean> => {\n      try {\n        if (!spaceId) throw new Error('Space ID is required');\n        if (!spaceName) throw new Error('Space name is required');\n        const normalizedSpaceId = spaceId.trim();\n        const normalizedSpaceName = spaceName.trim();\n\n        let targetFolderId: string | null = folderId || null;\n\n        // If folderId not provided, try to find the skill in current skills state\n        if (!targetFolderId) {\n          const skillInState = skills.find((s) => s.id === skillId);\n          if (skillInState && (skillInState as any)._folderId) {\n            targetFolderId = (skillInState as any)._folderId;\n          }\n        }\n\n        // Fallback: search in file system if not found\n        if (!targetFolderId) {\n          const spaceFolderId = await ensureSkillSpaceFolder(\n            normalizedSpaceName,","sourceCodeStart":987,"sourceCodeEnd":1023,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/web/src/pages/skills/hooks.ts#L987-L1023","documentation":"Thrown in web/src/pages/skills/hooks.ts:1005 by deleteSkill when the spaceId argument is falsy. Skill deletion needs the space id both to find the skill's folder and to clean up its search index entries, so an absent id is a caller-side error detected before any network activity. The catch wraps it into a generic 'skills.deleteError' toast.","triggerScenarios":"Calling deleteSkill without the spaceId positional argument; the spaces context not yet loaded so the active space id is undefined; refactor changed the parameter order (skillId, _skillName, spaceId, spaceName, folderId) and a caller passed them in the old order.","commonSituations":"Delete clicked before the space selector finished loading. Signature drift after the _skillName parameter was inserted, leaving older call sites misaligned. Space id stored as empty string in route state.","solutions":["Pass an options object ({skillId, spaceId, spaceName, folderId}) instead of positional args to prevent order bugs","Disable the delete action in the UI until the active space is resolved","Guard in the UI layer: if (!activeSpaceId) show a message instead of invoking deleteSkill","Grep all deleteSkill call sites to confirm argument alignment after the signature change"],"exampleFix":"// before\nconst deleteSkill = useCallback(\n  async (\n    skillId: string,\n    _skillName?: string,\n    spaceId?: string,\n    spaceName?: string,\n    folderId?: string,\n  ): Promise<boolean> => {\n    if (!spaceId) throw new Error('Space ID is required');\n\n// after\ntype DeleteSkillArgs = {\n  skillId: string;\n  spaceId: string;\n  spaceName: string;\n  folderId?: string;\n};\nconst deleteSkill = useCallback(\n  async ({ skillId, spaceId, spaceName, folderId }: DeleteSkillArgs) => {\n    if (!spaceId.trim() || !spaceName.trim()) {\n      message.error(t('skills.errors.spaceRequired'));\n      return false;\n    }","handlingStrategy":"validation","validationCode":"const canDelete = (skillId?: string, spaceId?: string, spaceName?: string) =>\n  [skillId, spaceId, spaceName].every((v) => typeof v === 'string' && v.trim().length > 0);","typeGuard":"const hasSpaceContext = (c: unknown): c is { spaceId: string; spaceName: string } =>\n  typeof c === 'object' && c !== null &&\n  typeof c.spaceId === 'string' && c.spaceId.length > 0 &&\n  typeof c.spaceName === 'string' && c.spaceName.length > 0;","tryCatchPattern":null,"preventionTips":["Switch deleteSkill to a single options-object parameter to end positional-arg drift","Gate the delete UI action on a resolved active space"],"tags":["validation","skills","typescript","delete"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}