langchain-ai/deepagents · error · ValueError
`expires_at` must be set when `logged_in` is True.
Error message
`expires_at` must be set when `logged_in` is True.
What it means
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.
Source
Thrown at libs/code/deepagents_code/integrations/openai_codex.py:109
cross-field rules the attribute docs promise — catching future
construction drift the same way upstream's `_ChatGPTToken` guards
its own invariants.
Raises:
ValueError: An unreadable token is also marked `logged_in`; a
logged-out snapshot carries an `expires_at`, `is_expired`,
`account_id`, or `plan_type`; or a logged-in snapshot is
missing its `expires_at`.
"""
if self.unreadable_reason is not None and self.logged_in:
msg = (
"`unreadable_reason` implies the token is not usable; "
"`logged_in` must be False."
)
raise ValueError(msg)
if self.logged_in and self.expires_at is None:
msg = "`expires_at` must be set when `logged_in` is True."
raise ValueError(msg)
if not self.logged_in and self.expires_at is not None:
msg = "`expires_at` is only meaningful when `logged_in` is True."
raise ValueError(msg)
if not self.logged_in and self.is_expired:
msg = "`is_expired` is only meaningful when `logged_in` is True."
raise ValueError(msg)
if not self.logged_in and (self.account_id or self.plan_type):
msg = (
"`account_id`/`plan_type` are only meaningful when `logged_in` is True."
)
raise ValueError(msg)
def default_store_path() -> Path:
"""Return the ChatGPT OAuth token store path.
Stored under Deep Agents' own state dir
(`~/.deepagents/.state/chatgpt-auth.json`) so the credential livesView on GitHub (pinned to a1af029e6e)
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.
Example fix
// before state = CodexAuthState(logged_in=True) // after state = CodexAuthState(logged_in=True, expires_at=now + timedelta(hours=1))
Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime, timezone
def valid_logged_in_state(state) -> bool:
return not (state.logged_in and state.expires_at is None) Try / catch
try:
state = CodexAuthState(logged_in=True, expires_at=expiry)
except ValueError:
state = CodexAuthState(logged_in=False, expires_at=None) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- `unreadable_reason` implies the token is not usable; `logged
- `expires_at` is only meaningful when `logged_in` is True.
- `is_expired` is only meaningful when `logged_in` is True.
- PendingNotification.key must be non-empty
- PendingNotification {self.key!r} must declare at least one a
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/4d5de481ffbbdfb5.
Report an issue: GitHub.