{"record":{"id":"e1a204c22893512a","repo":"google-gemini/gemini-cli","slug":"extension-validation-failed","errorCode":null,"errorMessage":"Extension validation failed.","messagePattern":"Extension validation failed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/extensions/validate.ts","lineNumber":87,"sourceCode":"  if (!semver.valid(extensionConfig.version)) {\n    warnings.push(\n      `Warning: Version '${extensionConfig.version}' does not appear to be standard semver (e.g., 1.0.0).`,\n    );\n  }\n\n  if (warnings.length > 0) {\n    debugLogger.warn('Validation warnings:');\n    for (const warning of warnings) {\n      debugLogger.warn(`  - ${warning}`);\n    }\n  }\n\n  if (errors.length > 0) {\n    debugLogger.error('Validation failed with the following errors:');\n    for (const error of errors) {\n      debugLogger.error(`  - ${error}`);\n    }\n    throw new Error('Extension validation failed.');\n  }\n}\n\nexport const validateCommand: CommandModule = {\n  command: 'validate <path>',\n  describe: 'Validates an extension from a local path.',\n  builder: (yargs) =>\n    yargs.positional('path', {\n      describe: 'The path of the extension to validate.',\n      type: 'string',\n      demandOption: true,\n    }),\n  handler: async (args) => {\n    await handleValidate({\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion\n      path: args['path'] as string,\n    });\n    await exitCli();","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/commands/extensions/validate.ts#L69-L105","documentation":"The 'gemini extensions validate' command runs structural checks on an extension directory. Currently it verifies that context files listed in gemini-extension.json's contextFileName field actually exist on disk. If any check produces an error, the individual errors are logged via debugLogger.error() and then this aggregate error is thrown.","triggerScenarios":"Running 'gemini extensions validate ./my-ext' where gemini-extension.json contains a contextFileName entry (e.g., 'docs/context.md') that does not exist as a file at the resolved path within the extension directory.","commonSituations":"Extension manifest references context files that were never created, were renamed, or have incorrect relative paths; packaging an extension without including all referenced files; case-sensitivity mismatch on Linux.","solutions":["Read the individual error messages logged before the throw to identify which files are missing.","Create the missing context files or fix their paths in gemini-extension.json.","Remove stale contextFileName entries from the manifest if the files are no longer needed."],"exampleFix":"// before (gemini-extension.json)\n{\n  \"contextFileName\": [\"docs/README.md\", \"docs/rules.md\"]\n}\n// docs/rules.md does not exist -> validation fails\n\n// after\n{\n  \"contextFileName\": [\"docs/README.md\"]\n}\n// or create docs/rules.md","handlingStrategy":"try-catch","validationCode":"import * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nfunction validateContextFilesExist(\n  extensionPath: string,\n  contextFileNames: string[] | string,\n): string[] {\n  const names = Array.isArray(contextFileNames) ? contextFileNames : [contextFileNames];\n  const missing: string[] = [];\n  for (const name of names) {\n    const abs = path.resolve(extensionPath, name);\n    if (!fs.existsSync(abs)) {\n      missing.push(name);\n    }\n  }\n  return missing;\n}\n\n// Pre-check before running validate:\nconst missing = validateContextFilesExist(extPath, config.contextFileName);\nif (missing.length > 0) {\n  console.error('Missing context files:', missing);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await handleValidate({ path: extPath });\n} catch (e) {\n  if (e instanceof Error && e.message === 'Extension validation failed.') {\n    // Individual errors were already logged by debugLogger.error\n    // Review the console output to see which checks failed\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Ensure all contextFileName entries in gemini-extension.json point to existing files.","Run 'gemini extensions validate' before publishing or installing an extension.","Use relative paths from the extension root in contextFileName.","Watch for case-sensitivity issues when developing on macOS/Windows and deploying on Linux."],"tags":["cli","extensions","validate","configuration"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}