{"record":{"id":"46886f410a07db63","repo":"google-gemini/gemini-cli","slug":"skill-installation-cancelled-by-user","errorCode":null,"errorMessage":"Skill installation cancelled by user.","messagePattern":"Skill installation cancelled by user\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"packages/cli/src/utils/skillUtils.ts","lineNumber":172,"sourceCode":"\n    onLog(`Searching for skills in ${sourcePath}...`);\n    const skills = await loadSkillsFromDir(sourcePath);\n\n    if (skills.length === 0) {\n      throw new Error(\n        `No valid skills found in ${source}${subpath ? ` at path \"${subpath}\"` : ''}. Ensure a SKILL.md file exists with valid frontmatter.`,\n      );\n    }\n\n    const workspaceDir = process.cwd();\n    const storage = new Storage(workspaceDir);\n    const targetDir =\n      scope === 'workspace'\n        ? storage.getProjectSkillsDir()\n        : Storage.getUserSkillsDir();\n\n    if (!(await requestConsent(skills, targetDir))) {\n      throw new Error('Skill installation cancelled by user.');\n    }\n\n    const resolvedTarget = path.resolve(targetDir);\n    await fs.mkdir(resolvedTarget, { recursive: true });\n\n    const installedSkills: Array<{ name: string; location: string }> = [];\n\n    for (const skill of skills) {\n      const skillName = skill.name;\n      const skillDir = path.dirname(skill.location);\n      const destPath = path.resolve(resolvedTarget, skillName);\n\n      const relative = path.relative(resolvedTarget, destPath);\n      if (isInvalidSubpath(relative)) {\n        throw new Error('Invalid skill name: Path traversal detected.');\n      }\n\n      const exists = await fs.lstat(destPath).catch(() => null);","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/utils/skillUtils.ts#L154-L190","documentation":"Thrown when requestConsent returns false — the user was prompted to approve skill installation and declined (or dismissed the prompt). This is an expected, user-initiated cancellation, not a system error.","triggerScenarios":"requestConsent(skills, targetDir) resolves to false. The interactive consent prompt received a 'no'/cancel, or non-interactive mode defaulted to decline.","commonSituations":"User chose not to trust a third-party skill. Running in a non-interactive context where the prompt cannot be answered. Consent policy set to auto-decline unknown sources.","solutions":["Re-run the install command and approve the consent prompt if you trust the source.","If running non-interactively, set the appropriate flag/env to auto-approve trusted sources (per the CLI's consent docs).","Verify the skill source is legitimate before approving."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// In non-interactive flows, decide explicitly whether to auto-approve.\nif (!process.stdin.isTTY && !AUTO_APPROVE_SKILLS) {\n  throw new Error('Skill consent cannot be obtained in non-interactive mode; set AUTO_APPROVE_SKILLS for trusted sources.');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run skill installs interactively when possible.","Only auto-approve skills from verified sources in CI."],"tags":["skill","installation","consent","user-action"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}