{"record":{"id":"8abecafd091b7206","repo":"phacility/phabricator","slug":"mailer-s-is-attempting-to-access-unknown-opti","errorCode":null,"errorMessage":"Mailer (\"%s\") is attempting to access unknown option (\"%s\").","messagePattern":"Mailer \\(\"(.+?)\"\\) is attempting to access unknown option \\(\"(.+?)\"\\)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/metamta/adapter/PhabricatorMailAdapter.php","lineNumber":121,"sourceCode":"    return $this;\n  }\n\n  final public function getSupportsInbound() {\n    return $this->supportsInbound;\n  }\n\n  final public function setSupportsOutbound($supports_outbound) {\n    $this->supportsOutbound = $supports_outbound;\n    return $this;\n  }\n\n  final public function getSupportsOutbound() {\n    return $this->supportsOutbound;\n  }\n\n  final public function getOption($key) {\n    if (!array_key_exists($key, $this->options)) {\n      throw new Exception(\n        pht(\n          'Mailer (\"%s\") is attempting to access unknown option (\"%s\").',\n          get_class($this),\n          $key));\n    }\n\n    return $this->options[$key];\n  }\n\n  final public function setOptions(array $options) {\n    $this->validateOptions($options);\n    $this->options = $options;\n    return $this;\n  }\n\n  abstract protected function validateOptions(array $options);\n\n  abstract public function newDefaultOptions();","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/metamta/adapter/PhabricatorMailAdapter.php#L103-L139","documentation":"Mail adapters read their configuration only through getOption($key), which serves keys present in the $options array installed by setOptions(). Phabricator's mailer factory merges each adapter's newDefaultOptions() with config before calling setOptions(), so in practice this exception means the adapter's own code asked for a key that its option schema never declared - a misspelled key name, or a caller that re-invoked setOptions() with a partial array and wiped the defaults.","triggerScenarios":"Writing or extending a PhabricatorMailAdapter subclass where getOption('api-key') does not match a key defined in newDefaultOptions()/validateOptions() (e.g. declared 'apikey' but read 'api-key'); calling setOptions($partial_options) directly, which validates then replaces the whole options array, dropping default keys the adapter later reads.","commonSituations":"Custom or third-party mail adapters written against an older option naming; upstream renames an option key while an install carries a local adapter patch; code that constructs adapters manually (tests, tooling) and forgets to merge newDefaultOptions().","solutions":["Compare the key in the exception message against the keys returned by the adapter's newDefaultOptions() and accepted by validateOptions() - they must match exactly.","Add the missing key to newDefaultOptions() (with a sensible default) and to the PhutilTypeSpec/checkMap in validateOptions().","Never call setOptions() with a partial array; build options as newDefaultOptions() + your overrides before handing them over.","If you are hitting this from config only, make sure the cluster.mailers 'options' keys use the exact names the adapter declares."],"exampleFix":"// before: adapter reads a key it never declares\npublic function newDefaultOptions() {\n  return array('apikey' => null);\n}\npublic function sendMessage($message) {\n  $key = $this->getOption('api-key'); // throws: unknown option\n}\n\n// after: declared key and read key match\npublic function newDefaultOptions() {\n  return array('api-key' => null);\n}\npublic function sendMessage($message) {\n  $key = $this->getOption('api-key');\n}","handlingStrategy":"validation","validationCode":"// When building adapters manually, always merge defaults before setOptions().\n$options = $adapter->newDefaultOptions() + $config_options;\n$adapter->setOptions($options);\n// And assert every key you will read is declared:\nforeach ($keys_you_read as $key) {\n  if (!array_key_exists($key, $options)) {\n    throw new Exception('Adapter option \"'.$key.'\" is not declared.');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In custom adapters, keep one constant/source for option key names and reference it from both newDefaultOptions()/validateOptions() and getOption() calls.","Never call setOptions() with a partial array - it replaces the entire option set."],"tags":["phabricator","metamta","mailer","configuration","adapter","missing-option"],"backgroundTag":"missing-config-key","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}