langchain-ai/langgraph · error · ValueError

Error executing TTL refresh

Error message

Error executing TTL refresh: 
{query.query}
{query.params}
{e}

What it means

A defensive wrapper inside AsyncSqliteStore's batch GET processing: the TTL refresh statement (UPDATE ... setting updated_at/expiry) for an item about to be read failed at the aiosqlite level, and the driver exception is re-raised as ValueError with the exact SQL and bound parameters appended for diagnosis. Root causes are typically a locked/busy database, schema drift, or an incompatible TTL table definition.

Solutions

  1. Inspect the query and params in the message to identify the failing statement and offending item
  2. If the database is locked, ensure only one writer at a time or enable WAL journaling
  3. If the TTL table schema was created by an older version, recreate the store schema so ttl_expired_at columns match the current code
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at libs/checkpoint-sqlite/langgraph/store/sqlite/aio.py:429 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of langchain-ai/langgraph@38031739e5 (2026-08-26). Data as JSON: /api/errors/41498532ed52ad37. Report an issue: GitHub.

Appendix: source

Thrown at libs/checkpoint-sqlite/langgraph/store/sqlite/aio.py:429

        Args:
            get_ops: Sequence of GET operations.
            results: List to store results in.
            cur: Database cursor.
        """
        # Group all queries by namespace to execute all operations for each namespace together
        namespace_queries = defaultdict(list)
        for prepared_query in self._get_batch_GET_ops_queries(get_ops):
            namespace_queries[prepared_query.namespace].append(prepared_query)

        # Process each namespace's operations
        for namespace, queries in namespace_queries.items():
            # Execute TTL refresh queries first
            for query in queries:
                if query.kind == "refresh":
                    try:
                        await cur.execute(query.query, query.params)
                    except Exception as e:
                        raise ValueError(
                            f"Error executing TTL refresh: \n{query.query}\n{query.params}\n{e}"
                        ) from e

            # Then execute GET queries and process results
            for query in queries:
                if query.kind == "get":
                    try:
                        await cur.execute(query.query, query.params)
                    except Exception as e:
                        raise ValueError(
                            f"Error executing GET query: \n{query.query}\n{query.params}\n{e}"
                        ) from e

                    rows = await cur.fetchall()
                    key_to_row = {
                        row[0]: {
                            "key": row[0],
                            "value": row[1],

View on GitHub (pinned to 38031739e5)