{"record":{"id":"b1fa7e47429a9f94","repo":"phacility/phabricator","slug":"value-s-is-not-valid-for-setting-s-valid-va","errorCode":null,"errorMessage":"Value \"%s\" is not valid for setting \"%s\": valid values are %s.","messagePattern":"Value \"(.+?)\" is not valid for setting \"(.+?)\": valid values are (.+?)\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"src/applications/settings/setting/PhabricatorOptionGroupSetting.php","lineNumber":54,"sourceCode":"\n    $flat_options = array();\n    foreach ($options as $group) {\n      $flat_options[$group['label']] = $group['options'];\n    }\n\n    return $this->newEditField($object, new PhabricatorSelectEditField())\n      ->setOptions($flat_options);\n  }\n\n  final public function validateTransactionValue($value) {\n    if (!strlen($value)) {\n      return;\n    }\n\n    $map = $this->getSelectOptionMap();\n\n    if (!isset($map[$value])) {\n      throw new Exception(\n        pht(\n          'Value \"%s\" is not valid for setting \"%s\": valid values are %s.',\n          $value,\n          $this->getSettingName(),\n          implode(', ', array_keys($map))));\n    }\n\n    return;\n  }\n\n  public function getTransactionNewValue($value) {\n    if (!strlen($value)) {\n      return null;\n    }\n\n    return (string)$value;\n  }\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/settings/setting/PhabricatorOptionGroupSetting.php#L36-L72","documentation":"Base class for settings rendered as grouped <select> dropdowns (PhabricatorSelectEditField with option groups). Its final validateTransactionValue() accepts the empty string (unset) but throws for any value not present as a key in getSelectOptionMap(). This stops stale, removed, or forged option keys from being persisted through settings transactions.","triggerScenarios":"Posting a settings transaction whose value is a key absent from the option map: a value removed in a newer release, a hand-crafted Conduit/settings request with an arbitrary string, or a cached form posting an old value after the option set changed.","commonSituations":"Downgrades or fork divergence where an option was removed; API clients hardcoding option keys; browser-cached settings forms submitting pre-upgrade values.","solutions":["Reload the settings form and pick from the currently offered options","If you maintain the setting class, either re-add the option or write a migration for stored values","For API writes, enumerate valid keys from getSelectOptionGroups()/getSelectOptionMap() at runtime instead of hardcoding"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isValidOptionGroupSettingValue(PhabricatorOptionGroupSetting $setting, $value) {\n  $value = phutil_string_cast($value);\n  if (!strlen($value)) { return true; } // empty = unset, allowed\n  return isset($setting->getSelectOptionMap()[$value]);\n}","tryCatchPattern":"try {\n  // write the setting\n} catch (Exception $ex) {\n  // value not in the option map: refetch current options and resubmit\n}","preventionTips":["Source enum values from the live option map, never from hardcoded copies","Re-render settings forms after upgrades before submitting","When renaming options in custom settings, keep legacy keys or migrate stored values"],"tags":["settings","enum","validation","select-options"],"backgroundTag":"invalid-enum-value","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}