{"record":{"id":"ece6a0b0e4705b58","repo":"phacility/phabricator","slug":"value-s-is-not-valid-for-setting-s-valid-va-ece6a0","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/PhabricatorSelectSetting.php","lineNumber":58,"sourceCode":"      throw new Exception(\n        pht(\n          'Empty string is not a valid setting for \"%s\".',\n          $this->getSettingName()));\n    }\n\n    $this->validateTransactionValue($value);\n  }\n\n  final public function validateTransactionValue($value) {\n    $value = phutil_string_cast($value);\n    if (!strlen($value)) {\n      return;\n    }\n\n    $options = $this->getSelectOptions();\n\n    if (!isset($options[$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($options))));\n    }\n\n    return;\n  }\n\n  public function getTransactionNewValue($value) {\n    $value = phutil_string_cast($value);\n\n    if (!strlen($value)) {\n      return null;\n    }\n\n    return $value;","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/settings/setting/PhabricatorSelectSetting.php#L40-L76","documentation":"Base class for settings rendered as flat <select> dropdowns. validateTransactionValue() first casts the value with phutil_string_cast() (so scalars become strings), allows empty (unset), then throws for any value not a key of getSelectOptions(). It guards the persisted enum against stale or forged keys, same contract as the option-group variant.","triggerScenarios":"A settings transaction whose value (after string cast) is not one of the declared option keys - removed options after an upgrade, arbitrary strings from crafted requests, or numeric values that cast to a string with no matching key.","commonSituations":"Version skew between a saved client form and current options; Conduit/API callers storing literal option keys; custom settings subclasses whose option list changed without migrating stored values.","solutions":["Submit a key exactly as listed in the current dropdown/options map","After upgrading, re-open the settings form so the client posts current keys","For custom settings, keep old keys as hidden/legacy options or migrate stored values when renaming"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isValidSelectSettingValue(PhabricatorSelectSetting $setting, $value) {\n  $value = phutil_string_cast($value);\n  if (!strlen($value)) { return true; } // empty = unset, allowed\n  return isset($setting->getSelectOptions()[$value]);\n}","tryCatchPattern":"try {\n  // write the setting\n} catch (Exception $ex) {\n  // invalid enum key: re-read the current options and resubmit\n}","preventionTips":["Always read option keys from the setting's option list at runtime","Avoid storing option keys long-term in API clients; refetch per session","After upgrades, exercise settings forms before automation touches them"],"tags":["settings","enum","validation","select-options"],"backgroundTag":"invalid-enum-value","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}