{"record":{"id":"c4cb9045091ff3dd","repo":"github/copilot-sdk","slug":"missing-required-fields-in-sessionmetadata-sessio","errorCode":null,"errorMessage":"Missing required fields in SessionMetadata: sessionId={session_id}, startTime={start_time}, modifiedTime={modified_time}, isRemote={is_remote}","messagePattern":"Missing required fields in SessionMetadata: sessionId=(.+?), startTime=(.+?), modifiedTime=(.+?), isRemote=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/copilot/client.py","lineNumber":1260,"sourceCode":"class SessionMetadata:\n    \"\"\"Metadata about a session\"\"\"\n\n    session_id: str  # Session identifier\n    start_time: datetime  # Timestamp when session was created\n    modified_time: datetime  # Timestamp when session was last modified\n    is_remote: bool  # Whether the session is remote\n    summary: str | None = None  # Optional summary of the session\n    context: SessionContext | None = None  # Working directory context\n\n    @staticmethod\n    def from_dict(obj: Any) -> SessionMetadata:\n        assert isinstance(obj, dict)\n        session_id = obj.get(\"sessionId\")\n        start_time = obj.get(\"startTime\")\n        modified_time = obj.get(\"modifiedTime\")\n        is_remote = obj.get(\"isRemote\")\n        if session_id is None or start_time is None or modified_time is None or is_remote is None:\n            raise ValueError(\n                f\"Missing required fields in SessionMetadata: sessionId={session_id}, \"\n                f\"startTime={start_time}, modifiedTime={modified_time}, isRemote={is_remote}\"\n            )\n        summary = obj.get(\"summary\")\n        context_dict = obj.get(\"context\")\n        context = SessionContext.from_dict(context_dict) if context_dict else None\n        return SessionMetadata(\n            session_id=str(session_id),\n            start_time=_parse_session_timestamp(start_time),\n            modified_time=_parse_session_timestamp(modified_time),\n            is_remote=bool(is_remote),\n            summary=summary,\n            context=context,\n        )\n\n    def to_dict(self) -> dict:\n        result: dict = {}\n        result[\"sessionId\"] = self.session_id","sourceCodeStart":1242,"sourceCodeEnd":1278,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/client.py#L1242-L1278","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add all four required keys (sessionId, startTime, modifiedTime, isRemote) to the dict before calling from_dict","Validate the dict with a helper that checks for the required keys first","Check the source of the JSON: if it uses snake_case (session_id, start_time), rename keys to camelCase before deserializing","If the data comes from an old export, regenerate it with a current version of the tool so all fields are present"],"exampleFix":"// before\nmeta = SessionMetadata.from_dict({\"sessionId\": \"s1\", \"startTime\": \"2024-01-01\"})\n# after\nmeta = SessionMetadata.from_dict({\n    \"sessionId\": \"s1\",\n    \"startTime\": \"2024-01-01T00:00:00Z\",\n    \"modifiedTime\": \"2024-01-01T01:00:00Z\",\n    \"isRemote\": False,\n})","handlingStrategy":"validation","validationCode":"required = {\"sessionId\", \"startTime\", \"modifiedTime\", \"isRemote\"}\nif not required.issubset(data.keys()):\n    raise ValueError(f\"missing: {required - data.keys()}\")\nSessionMetadata.from_dict(data)","typeGuard":"def has_session_fields(obj: dict) -> bool:\n    return all(obj.get(k) is not None for k in (\"sessionId\", \"startTime\", \"modifiedTime\", \"isRemote\"))","tryCatchPattern":"try:\n    meta = SessionMetadata.from_dict(data)\nexcept ValueError as e:\n    logger.error(\"bad session metadata: %s\", e)\n    meta = None","preventionTips":["Validate payloads against the SessionMetadata schema before from_dict","Normalize snake_case keys to camelCase when ingesting external JSON","Add a round-trip serialization test for session metadata"],"tags":["python","deserialization","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}