{"record":{"id":"71ae25b59ae994ee","repo":"github/copilot-sdk","slug":"missing-required-fields-in-modelpolicy-state-sta","errorCode":null,"errorMessage":"Missing required fields in ModelPolicy: state={state}, terms={terms}","messagePattern":"Missing required fields in ModelPolicy: state=(.+?), terms=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/copilot/client.py","lineNumber":1084,"sourceCode":"        result[\"supports\"] = self.supports.to_dict()\n        result[\"limits\"] = self.limits.to_dict()\n        return result\n\n\n@dataclass\nclass ModelPolicy:\n    \"\"\"Model policy state\"\"\"\n\n    state: str  # \"enabled\", \"disabled\", or \"unconfigured\"\n    terms: str\n\n    @staticmethod\n    def from_dict(obj: Any) -> ModelPolicy:\n        assert isinstance(obj, dict)\n        state = obj.get(\"state\")\n        terms = obj.get(\"terms\")\n        if state is None or terms is None:\n            raise ValueError(\n                f\"Missing required fields in ModelPolicy: state={state}, terms={terms}\"\n            )\n        return ModelPolicy(state=str(state), terms=str(terms))\n\n    def to_dict(self) -> dict:\n        result: dict = {}\n        result[\"state\"] = self.state\n        result[\"terms\"] = self.terms\n        return result\n\n\n@dataclass\nclass ModelBilling:\n    \"\"\"Model billing information\"\"\"\n\n    multiplier: float | None = None\n    token_prices: ModelBillingTokenPrices | None = None\n","sourceCodeStart":1066,"sourceCodeEnd":1102,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/client.py#L1066-L1102","documentation":"ModelPolicy.from_dict requires both 'state' and 'terms' keys in a model's policy object and raises ValueError when either is missing/None. The library models per-model policy (enablement state plus terms) as mandatory so downstream code can rely on both values.","triggerScenarios":"The models/list response contains a model whose 'policy' object lacks 'state' or 'terms'; a server or mock emits policy as {} or with only one key.","commonSituations":"Newer/older server builds with a changed model-policy schema; models listed in preview states that omit terms; cached or mocked model catalogs in tests.","solutions":["Update the server/client versions so model policy payloads include both 'state' and 'terms'","Filter or skip models whose policy payload is incomplete before decoding","Fix fixtures/mocks to include a complete policy: {'state': ..., 'terms': ...}"],"exampleFix":"// before (mock)\n{\"policy\": {\"state\": \"enabled\"}}\n// after\n{\"policy\": {\"state\": \"enabled\", \"terms\": \"https://example.com/terms\"}}","handlingStrategy":"validation","validationCode":"def is_complete_model_policy(p: dict | None) -> bool:\n    return isinstance(p, dict) and p.get(\"state\") is not None and p.get(\"terms\") is not None","typeGuard":"def has_model_policy(model: dict) -> bool:\n    p = model.get(\"policy\")\n    return isinstance(p, dict) and \"state\" in p and \"terms\" in p","tryCatchPattern":"try:\n    policy = ModelPolicy.from_dict(model[\"policy\"])\nexcept ValueError as e:\n    if str(e).startswith(\"Missing required fields in ModelPolicy\"):\n        policy = None  # treat model as policy-less\n    else:\n        raise","preventionTips":["Validate model-catalog entries before batch decoding","Skip models with incomplete policy objects rather than failing the whole list","Pin client/server versions so the model-policy schema matches"],"tags":["python","deserialization","model-policy","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}