{"record":{"id":"4fb2c52412aab561","repo":"ZhuLinsen/daily_stock_analysis","slug":"field-name-must-be-one-of-allowed","errorCode":null,"errorMessage":"{field_name} must be one of: {allowed}","messagePattern":"(.+?) must be one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"src/schemas/decision_profile.py","lineNumber":65,"sourceCode":"DECISION_PROFILE_FILTER_UNKNOWN = DecisionProfileFilter(\"unknown\")\n\n\ndef normalize_decision_profile(\n    value: Any,\n    *,\n    field_name: str = \"decision_profile\",\n) -> Optional[DecisionProfile]:\n    \"\"\"Return a normalized profile or raise for a non-empty invalid value.\"\"\"\n\n    if value in (None, \"\"):\n        return None\n    text = str(value).strip().lower()\n    if not text:\n        return None\n    if text in VALID_DECISION_PROFILES:\n        return text  # type: ignore[return-value]\n    allowed = \", \".join(VALID_DECISION_PROFILES)\n    raise ValueError(f\"{field_name} must be one of: {allowed}\")\n\n\ndef normalize_decision_profile_filter(value: Any) -> DecisionProfileFilter:\n    \"\"\"Normalize list-filter input while preserving all-vs-unknown semantics.\"\"\"\n\n    if value in (None, \"\"):\n        return DECISION_PROFILE_FILTER_ALL\n    text = str(value).strip().lower()\n    if not text:\n        return DECISION_PROFILE_FILTER_ALL\n    if text == DECISION_PROFILE_UNKNOWN:\n        return DECISION_PROFILE_FILTER_UNKNOWN\n    profile = normalize_decision_profile(text, field_name=\"decision_profile\")\n    return DecisionProfileFilter(\"profile\", profile)\n\n\ndef extract_legacy_decision_profile(metadata: Any) -> Optional[DecisionProfile]:\n    \"\"\"Extract a legal legacy profile from metadata; invalid values are ignored.\"\"\"","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/schemas/decision_profile.py#L47-L83","documentation":"ValueError from the decision-profile normalizer when a supplied profile value is non-empty but not in VALID_DECISION_PROFILES. Profiles are a closed, lowercased enum (field_name defaults to 'decision_profile' and is used in the message); empty/None passes through as no profile, everything else must match exactly after strip+lower.","triggerScenarios":"Passing decision_profile='aggressive', 'steady', 'balanced ' (trailing junk), or any string not in the allowed set through a query param, API payload, or CLI flag. Normalization lowercases and strips, so the failure means the value is genuinely outside the enum, not a casing issue.","commonSituations":"API consumers guessing profile names; a renamed profile after an upgrade while old clients keep sending the previous value; typos; passing a profile filter value where a single profile is required.","solutions":["Check the error message — it lists the allowed values verbatim; use one of those","Fix typos and remove extra tokens; note normalization handles case and surrounding whitespace already","On the client side, source profile names from the API's enumeration endpoint or constants instead of hardcoding strings","After renames/upgrades, update stored user preferences or configs that reference retired profile names"],"exampleFix":"# before\nGET /api/decisions?decision_profile=aggressive\n\n# after\nGET /api/decisions?decision_profile=<one of the values listed in the error>","handlingStrategy":"validation","validationCode":"from src.schemas.decision_profile import VALID_DECISION_PROFILES\n\ndef is_valid_decision_profile(value: str) -> bool:\n    return (value or \"\").strip().lower() in VALID_DECISION_PROFILES","typeGuard":"from typing import Any\nfrom src.schemas.decision_profile import VALID_DECISION_PROFILES\n\ndef is_decision_profile(value: Any) -> bool:\n    return isinstance(value, str) and value.strip().lower() in VALID_DECISION_PROFILES","tryCatchPattern":"try:\n    profile = normalize_decision_profile(request.args.get(\"decision_profile\"))\nexcept ValueError as exc:\n    return bad_request(str(exc))  # echoes allowed values","preventionTips":["Serve allowed values from an enum endpoint and use dropdowns on clients","Validate at the API boundary and return 400 with the allowed list","Migrate stored profile strings during renames instead of rejecting old clients"],"tags":["validation","api","enum","schema"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}