github/copilot-sdk · error · ValueError

Missing required fields in PingResponse: message=

Error message

Missing required fields in PingResponse: message={message}, timestamp={timestamp}, protocolVersion={protocol_version}

What it means

PingResponse.from_dict validates the raw JSON-RPC payload from the server and requires 'message', 'timestamp' (epoch millis), and 'protocolVersion' to be present. If any is missing/None it raises ValueError listing the offending values. This guards against decoding an incomplete or malformed ping response into a dataclass.

Solutions

  1. Upgrade/align the Copilot server so its ping response includes message, timestamp, and protocolVersion
  2. Fix test mocks/stubs to return all three fields (timestamp as int/float epoch milliseconds)
  3. Check for proxies or response-rewriting middleware that drop fields
  4. Verify client and server protocol versions match

Example fix

// before (test stub)
return {"message": "pong"}
// after
import time
return {"message": "pong", "timestamp": int(time.time() * 1000), "protocolVersion": 1}
Defensive patterns

Strategy: try-catch

Validate before calling

def is_valid_ping_payload(obj) -> bool:
    return isinstance(obj, dict) and all(obj.get(k) is not None for k in ("message", "timestamp", "protocolVersion"))

Type guard

def is_ping_response(obj: object) -> bool:
    return (
        isinstance(obj, dict)
        and isinstance(obj.get("message"), str)
        and isinstance(obj.get("timestamp"), (int, float))
        and "protocolVersion" in obj
    )

Try / catch

try:
    ping = PingResponse.from_dict(payload)
except ValueError as e:
    if str(e).startswith("Missing required fields in PingResponse"):
        logger.error("malformed ping payload: %s", payload)
        ping = None  # or reconnect / re-handshake
    else:
        raise

Prevention

When it happens

Trigger: The server (or a proxy/test stub) returns a ping payload omitting message, timestamp, or protocolVersion; a mock returning partial dicts; a protocol downgrade where older servers omit protocolVersion.

Common situations: Pinning against an older server build whose ping schema differs; unit-test fakes that return {'message': 'pong'} only; custom middleware stripping fields; version mismatch between client expectations and server build.

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/e361f87a80908aeb. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/client.py:849

# ============================================================================


@dataclass
class PingResponse:
    """Response from ping"""

    message: str  # Echo message with "pong: " prefix
    timestamp: datetime  # Timestamp when the ping was processed
    protocol_version: int  # Protocol version for SDK compatibility

    @staticmethod
    def from_dict(obj: Any) -> PingResponse:
        assert isinstance(obj, dict)
        message = obj.get("message")
        timestamp = obj.get("timestamp")
        protocol_version = obj.get("protocolVersion")
        if message is None or timestamp is None or protocol_version is None:
            raise ValueError(
                f"Missing required fields in PingResponse: message={message}, "
                f"timestamp={timestamp}, protocolVersion={protocol_version}"
            )
        timestamp_value = (
            datetime.fromtimestamp(timestamp / 1000, tz=UTC)
            if isinstance(timestamp, (int, float))
            else from_datetime(timestamp)
        )
        return PingResponse(str(message), timestamp_value, int(protocol_version))

    def to_dict(self) -> dict:
        result: dict = {}
        result["message"] = self.message
        result["timestamp"] = self.timestamp.isoformat()
        result["protocolVersion"] = self.protocol_version
        return result

View on GitHub (pinned to cd8cf15dc3)