{"record":{"id":"4d5de481ffbbdfb5","repo":"langchain-ai/deepagents","slug":"expires-at-must-be-set-when-logged-in-is-true","errorCode":null,"errorMessage":"`expires_at` must be set when `logged_in` is True.","messagePattern":"`expires_at` must be set when `logged_in` is True\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/integrations/openai_codex.py","lineNumber":109,"sourceCode":"        cross-field rules the attribute docs promise — catching future\n        construction drift the same way upstream's `_ChatGPTToken` guards\n        its own invariants.\n\n        Raises:\n            ValueError: An unreadable token is also marked `logged_in`; a\n                logged-out snapshot carries an `expires_at`, `is_expired`,\n                `account_id`, or `plan_type`; or a logged-in snapshot is\n                missing its `expires_at`.\n        \"\"\"\n        if self.unreadable_reason is not None and self.logged_in:\n            msg = (\n                \"`unreadable_reason` implies the token is not usable; \"\n                \"`logged_in` must be False.\"\n            )\n            raise ValueError(msg)\n        if self.logged_in and self.expires_at is None:\n            msg = \"`expires_at` must be set when `logged_in` is True.\"\n            raise ValueError(msg)\n        if not self.logged_in and self.expires_at is not None:\n            msg = \"`expires_at` is only meaningful when `logged_in` is True.\"\n            raise ValueError(msg)\n        if not self.logged_in and self.is_expired:\n            msg = \"`is_expired` is only meaningful when `logged_in` is True.\"\n            raise ValueError(msg)\n        if not self.logged_in and (self.account_id or self.plan_type):\n            msg = (\n                \"`account_id`/`plan_type` are only meaningful when `logged_in` is True.\"\n            )\n            raise ValueError(msg)\n\n\ndef default_store_path() -> Path:\n    \"\"\"Return the ChatGPT OAuth token store path.\n\n    Stored under Deep Agents' own state dir\n    (`~/.deepagents/.state/chatgpt-auth.json`) so the credential lives","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/integrations/openai_codex.py#L91-L127","documentation":"A `__post_init__` invariant in the Codex integration token state: when `logged_in` is True the object must carry an `expires_at` timestamp so callers can reason about token expiry. A logged-in state without an expiration is considered malformed and rejected with ValueError.","triggerScenarios":"Constructing the dataclass with `logged_in=True` and `expires_at=None`, e.g. `TokenState(logged_in=True)` or loading a persisted snapshot whose expiry field was missing.","commonSituations":"Parsing an auth file that lacks an expiry claim, migrating old token caches that stored no expiration, or manually constructing the state in tests without all fields.","solutions":["Pass a concrete `expires_at` (e.g. `datetime.now(timezone.utc) + token_lifetime`) when `logged_in=True`.","If the expiry is genuinely unknown, set `logged_in=False` and re-authenticate.","Fix the persistence layer to always serialize `expires_at` alongside the login flag."],"exampleFix":"// before\nstate = CodexAuthState(logged_in=True)\n// after\nstate = CodexAuthState(logged_in=True, expires_at=now + timedelta(hours=1))","handlingStrategy":"validation","validationCode":"from datetime import datetime, timezone\ndef valid_logged_in_state(state) -> bool:\n    return not (state.logged_in and state.expires_at is None)","typeGuard":null,"tryCatchPattern":"try:\n    state = CodexAuthState(logged_in=True, expires_at=expiry)\nexcept ValueError:\n    state = CodexAuthState(logged_in=False, expires_at=None)","preventionTips":["Never construct logged_in=True without computing expires_at from the token's exp claim","Fix persistence to serialize expires_at with the login flag","Use a factory function that derives expires_at automatically"],"tags":["python","validation","dataclass","auth"],"backgroundTag":"invariant-validation-failed","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}