{"record":{"id":"29822dbf469dbaaf","repo":"tursodatabase/turso","slug":"query-timeout-must-be-non-negative","errorCode":null,"errorMessage":"query timeout must be non-negative","messagePattern":"query timeout must be non-negative","errorType":"exception","errorClass":"ProgrammingError","httpStatus":null,"severity":"error","filePath":"bindings/python/turso/lib.py","lineNumber":556,"sourceCode":"        ``OperationalError`` (\"interrupted\"). The underlying execution methods\n        release the GIL, so a watchdog thread can actually run while a query is\n        busy. If no statement is running the call is a no-op.\n        \"\"\"\n        try:\n            self._conn.interrupt()\n        except Exception as exc:  # noqa: BLE001\n            raise _map_turso_exception(exc)\n\n    def set_query_timeout(self, milliseconds: int) -> None:\n        \"\"\"\n        Set the maximum time (in milliseconds) a single statement may run before\n        it is interrupted (raising ``OperationalError``). ``0`` disables the\n        timeout. Unlike ``interrupt()`` this needs no watchdog thread: the\n        deadline is enforced inside the engine. Turso extension (not in stdlib\n        ``sqlite3``).\n        \"\"\"\n        if milliseconds < 0:\n            raise ProgrammingError(\"query timeout must be non-negative\")\n        try:\n            self._conn.set_query_timeout(milliseconds)\n        except Exception as exc:  # noqa: BLE001\n            raise _map_turso_exception(exc)\n\n    def get_query_timeout(self) -> int:\n        \"\"\"Return the current per-statement query timeout in milliseconds (``0`` = disabled).\"\"\"\n        try:\n            return self._conn.get_query_timeout()\n        except Exception as exc:  # noqa: BLE001\n            raise _map_turso_exception(exc)\n\n    def _maybe_implicit_begin(self, sql: str) -> None:\n        \"\"\"\n        Implement sqlite3 legacy implicit transaction behavior:\n\n        If autocommit is LEGACY_TRANSACTION_CONTROL, isolation_level is not None, sql is a DML\n        (INSERT/UPDATE/DELETE/REPLACE), and there is no open transaction, issue:","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/bindings/python/turso/lib.py#L538-L574","documentation":"Connection.set_query_timeout(milliseconds) in pyturso sets a per-statement deadline enforced inside the engine, with 0 meaning 'disabled'. The Python wrapper checks the argument before it reaches the engine and raises ProgrammingError for any negative number. The negative value never reaches the Rust core; it is rejected at the API boundary.","triggerScenarios":"Calling conn.set_query_timeout(-1) directly, or passing a computed value like (deadline_ms - now_ms) that has already gone negative because the deadline is in the past. Also passing seconds where milliseconds are expected makes surprising values but only negative ones raise.","commonSituations":"Deadline math based on wall-clock time that expires before the call; code ported from APIs where -1 means 'no timeout'; unit confusion between seconds and milliseconds.","solutions":["Pass 0 to disable the timeout instead of a negative value","Clamp computed deadlines before the call: set_query_timeout(max(0, remaining_ms))","If you meant seconds, multiply by 1000 and pass a non-negative result"],"exampleFix":"// before\nconn.set_query_timeout(remaining_ms)  // remaining_ms can be -500 after a slow retry\n\n// after\nconn.set_query_timeout(max(0, remaining_ms))","handlingStrategy":"validation","validationCode":"def safe_set_query_timeout(conn, milliseconds: int) -> None:\n    if milliseconds < 0:\n        raise ValueError(f\"timeout must be >= 0, got {milliseconds}\")\n    conn.set_query_timeout(milliseconds)","typeGuard":null,"tryCatchPattern":"from turso.lib import ProgrammingError\n\ntry:\n    conn.set_query_timeout(ms)\nexcept ProgrammingError:\n    conn.set_query_timeout(0)  # fall back to 'disabled'","preventionTips":["Treat 0 as the only 'disabled' sentinel, never -1","Compute deadlines with time.monotonic() so remaining time stays meaningful","Validate duration inputs at your own API boundary before they reach the driver"],"tags":["python","db-api","timeout","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}