github/copilot-sdk · error · ValueError

Missing required fields in SessionMetadata: sessionId=

Error message

Missing required fields in SessionMetadata: sessionId={session_id}, startTime={start_time}, modifiedTime={modified_time}, isRemote={is_remote}

What it means

SessionMetadata.from_dict requires four mandatory keys: sessionId, startTime, modifiedTime, and isRemote. The library raises ValueError when any of them is absent (None) in the input dict, because a session cannot be tracked without identity and timestamps.

Solutions

  1. Add all four required keys (sessionId, startTime, modifiedTime, isRemote) to the dict before calling from_dict
  2. Validate the dict with a helper that checks for the required keys first
  3. Check the source of the JSON: if it uses snake_case (session_id, start_time), rename keys to camelCase before deserializing
  4. If the data comes from an old export, regenerate it with a current version of the tool so all fields are present

Example fix

// before
meta = SessionMetadata.from_dict({"sessionId": "s1", "startTime": "2024-01-01"})
# after
meta = SessionMetadata.from_dict({
    "sessionId": "s1",
    "startTime": "2024-01-01T00:00:00Z",
    "modifiedTime": "2024-01-01T01:00:00Z",
    "isRemote": False,
})
Defensive patterns

Strategy: validation

Validate before calling

required = {"sessionId", "startTime", "modifiedTime", "isRemote"}
if not required.issubset(data.keys()):
    raise ValueError(f"missing: {required - data.keys()}")
SessionMetadata.from_dict(data)

Type guard

def has_session_fields(obj: dict) -> bool:
    return all(obj.get(k) is not None for k in ("sessionId", "startTime", "modifiedTime", "isRemote"))

Try / catch

try:
    meta = SessionMetadata.from_dict(data)
except ValueError as e:
    logger.error("bad session metadata: %s", e)
    meta = None

Prevention

When it happens

Trigger: Calling SessionMetadata.from_dict() with a dict missing one or more of sessionId/startTime/modifiedTime/isRemote, e.g. deserializing a truncated or hand-crafted session JSON payload.

Common situations: Parsing session files exported by older library versions that lacked modifiedTime; hand-written test fixtures with only partial fields; JSON produced by a different tool that uses snake_case keys instead of camelCase.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at python/copilot/client.py:1260

class SessionMetadata:
    """Metadata about a session"""

    session_id: str  # Session identifier
    start_time: datetime  # Timestamp when session was created
    modified_time: datetime  # Timestamp when session was last modified
    is_remote: bool  # Whether the session is remote
    summary: str | None = None  # Optional summary of the session
    context: SessionContext | None = None  # Working directory context

    @staticmethod
    def from_dict(obj: Any) -> SessionMetadata:
        assert isinstance(obj, dict)
        session_id = obj.get("sessionId")
        start_time = obj.get("startTime")
        modified_time = obj.get("modifiedTime")
        is_remote = obj.get("isRemote")
        if session_id is None or start_time is None or modified_time is None or is_remote is None:
            raise ValueError(
                f"Missing required fields in SessionMetadata: sessionId={session_id}, "
                f"startTime={start_time}, modifiedTime={modified_time}, isRemote={is_remote}"
            )
        summary = obj.get("summary")
        context_dict = obj.get("context")
        context = SessionContext.from_dict(context_dict) if context_dict else None
        return SessionMetadata(
            session_id=str(session_id),
            start_time=_parse_session_timestamp(start_time),
            modified_time=_parse_session_timestamp(modified_time),
            is_remote=bool(is_remote),
            summary=summary,
            context=context,
        )

    def to_dict(self) -> dict:
        result: dict = {}
        result["sessionId"] = self.session_id

View on GitHub (pinned to cd8cf15dc3)