{"record":{"id":"6b7c7a7ce200508a","repo":"SeleniumHQ/selenium","slug":"could-not-find-add-on-id-for-extension","errorCode":null,"errorMessage":"Could not find add-on ID for ${extension}","messagePattern":"Could not find add-on ID for (.+?)","errorType":"validation","errorClass":"AddonFormatError","httpStatus":null,"severity":"error","filePath":"javascript/selenium-webdriver/firefox.js","lineNumber":177,"sourceCode":"  let parsedJSON = JSON.parse(buf.toString('utf8'))\n\n  let { browser_specific_settings } =\n    /** @type {{browser_specific_settings:{gecko:{id:string}}}} */\n    parsedJSON\n\n  if (browser_specific_settings && browser_specific_settings.gecko) {\n    /* browser_specific_settings is an alternative to applications\n     * It is meant to facilitate cross-browser plugins since Firefox48\n     * see https://bugzilla.mozilla.org/show_bug.cgi?id=1262005\n     */\n    parsedJSON.applications = browser_specific_settings\n  }\n\n  let { applications } =\n    /** @type {{applications:{gecko:{id:string}}}} */\n    parsedJSON\n  if (!(applications && applications.gecko && applications.gecko.id)) {\n    throw new AddonFormatError(`Could not find add-on ID for ${extension}`)\n  }\n\n  await io.copy(extension, `${path.join(dir, applications.gecko.id)}.xpi`)\n  return applications.gecko.id\n}\n\nclass Profile {\n  constructor() {\n    /** @private {?string} */\n    this.template_ = null\n\n    /** @private {!Array<string>} */\n    this.extensions_ = []\n  }\n\n  addExtensions(/** !Array<string> */ paths) {\n    this.extensions_ = this.extensions_.concat(...paths)\n  }","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/javascript/selenium-webdriver/firefox.js#L159-L195","documentation":"Thrown by installExtension() in firefox.js when the parsed manifest.json lacks a Firefox add-on ID. The code checks browser_specific_settings.gecko.id then falls back to applications.gecko.id; if neither yields an ID, this error fires. Firefox requires a stable add-on ID to install extensions into a profile.","triggerScenarios":"The extension manifest has no applications or browser_specific_settings block. The gecko.id field is missing or empty. Using a manifest V3 extension without gecko-specific settings.","commonSituations":"Developing/testing an unsigned local extension without declaring an ID; porting a Chrome extension (which has no gecko ID requirement); manifest generated by a tool that omits the gecko block.","solutions":["Add browser_specific_settings: { gecko: { id: 'your-addon@your-domain.com' } } to manifest.json.","Alternatively set applications.gecko.id (legacy key, still read by the code).","Ensure the ID follows the Firefox format (email-like or UUID format)."],"exampleFix":"// before — manifest.json has no gecko id\n{\n  \"manifest_version\": 2,\n  \"name\": \"My Ext\",\n  \"version\": \"1.0\"\n}\n// after\n{\n  \"manifest_version\": 2,\n  \"name\": \"My Ext\",\n  \"version\": \"1.0\",\n  \"browser_specific_settings\": {\n    \"gecko\": { \"id\": \"my-ext@example.com\" }\n  }\n}","handlingStrategy":"validation","validationCode":"function validateManifestHasGeckoId(manifest) {\n  const id =\n    manifest?.browser_specific_settings?.gecko?.id ??\n    manifest?.applications?.gecko?.id\n  if (!id) {\n    throw new Error('manifest.json must define browser_specific_settings.gecko.id or applications.gecko.id')\n  }\n  return id\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include browser_specific_settings.gecko.id in Firefox extension manifests.","Use an email-like or UUID format for the add-on ID.","Validate the manifest with web-ext lint before packaging.","When porting from Chrome, add the gecko block explicitly."],"tags":["firefox","extension","manifest","addon","validation"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}