github/copilot-sdk · error · ValueError

Missing required fields in ModelInfo: id=

Error message

Missing required fields in ModelInfo: id={id}, name={name}, capabilities={capabilities_dict}

What it means

ModelInfo.from_dict requires 'id', 'name', and 'capabilities' in each model entry of the model catalog and raises ValueError listing the missing values otherwise. Optional 'policy' is decoded only when present, but id/name/capabilities are mandatory to build a usable ModelInfo.

Solutions

  1. Upgrade/align the server so every model entry includes id, name, and capabilities
  2. Skip or repair incomplete entries before calling from_dict (validate keys first)
  3. Update mocks/fixtures to include a capabilities object compatible with ModelCapabilities.from_dict

Example fix

// before (fixture)
{"id": "gpt-4o", "name": "GPT-4o"}
// after
{"id": "gpt-4o", "name": "GPT-4o", "capabilities": {"supports": {}}}
# (capabilities object must satisfy ModelCapabilities.from_dict)
Defensive patterns

Strategy: validation

Validate before calling

def model_entry_is_decodable(m: dict) -> bool:
    return (
        isinstance(m, dict)
        and m.get("id") is not None
        and m.get("name") is not None
        and m.get("capabilities") is not None
    )
models = [ModelInfo.from_dict(m) for m in raw if model_entry_is_decodable(m)]

Type guard

def is_model_entry(obj: object) -> bool:
    return isinstance(obj, dict) and {"id", "name", "capabilities"} <= obj.keys()

Try / catch

try:
    info = ModelInfo.from_dict(entry)
except ValueError as e:
    if str(e).startswith("Missing required fields in ModelInfo"):
        logger.warning("skipping malformed model entry: %s", entry)
        info = None
    else:
        raise

Prevention

When it happens

Trigger: The list-models response contains an entry missing 'id', 'name', or 'capabilities'; a minimal mock returns only {'id': ..., 'name': ...}; a server-side schema change renames or drops 'capabilities'.

Common situations: Version drift between client schema expectations and server model catalog; aggregating models from multiple backends where one omits capabilities; hand-written test fixtures.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/ac59922c434eb339. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/client.py:1144

    id: str  # Model identifier (e.g., "claude-sonnet-4.5")
    name: str  # Display name
    capabilities: ModelCapabilities  # Model capabilities and limits
    policy: ModelPolicy | None = None  # Policy state
    billing: ModelBilling | None = None  # Billing information
    # Supported reasoning effort levels (only present if model supports reasoning effort)
    supported_reasoning_efforts: list[str] | None = None
    # Default reasoning effort level (only present if model supports reasoning effort)
    default_reasoning_effort: str | None = None

    @staticmethod
    def from_dict(obj: Any) -> ModelInfo:
        assert isinstance(obj, dict)
        id = obj.get("id")
        name = obj.get("name")
        capabilities_dict = obj.get("capabilities")
        if id is None or name is None or capabilities_dict is None:
            raise ValueError(
                f"Missing required fields in ModelInfo: id={id}, name={name}, "
                f"capabilities={capabilities_dict}"
            )
        capabilities = ModelCapabilities.from_dict(capabilities_dict)
        policy_dict = obj.get("policy")
        policy = ModelPolicy.from_dict(policy_dict) if policy_dict else None
        billing_dict = obj.get("billing")
        billing = ModelBilling.from_dict(billing_dict) if billing_dict else None
        supported_reasoning_efforts = obj.get("supportedReasoningEfforts")
        default_reasoning_effort = obj.get("defaultReasoningEffort")
        return ModelInfo(
            id=str(id),
            name=str(name),
            capabilities=capabilities,
            policy=policy,
            billing=billing,
            supported_reasoning_efforts=supported_reasoning_efforts,
            default_reasoning_effort=default_reasoning_effort,

View on GitHub (pinned to cd8cf15dc3)