{"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":454,"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":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/python/turso/lib.py#L436-L472","documentation":"Connection.set_query_timeout validates that milliseconds is >= 0 before calling into the engine; 0 disables the timeout. A negative value raises ProgrammingError immediately, since a deadline in the past is meaningless.","triggerScenarios":"`conn.set_query_timeout(-1)` intending \"no timeout\" (the correct value is 0), or a computed timeout like `int((deadline - time.time()) * 1000)` that goes negative once the deadline passes.","commonSituations":"Deadline arithmetic racing the clock; request-scoped timeouts derived from already-expired budgets; copying semantics from APIs where -1 means infinite.","solutions":["Clamp computed values: conn.set_query_timeout(max(0, ms))","Use 0 to disable the timeout, not a negative number","If a computed timeout is already <= 0, skip the statement entirely — it is past budget"],"exampleFix":"# before\nremaining_ms = int((deadline - time.time()) * 1000)  # can be negative\nconn.set_query_timeout(remaining_ms)\n\n# after\nremaining_ms = int((deadline - time.time()) * 1000)\nif remaining_ms <= 0:\n    raise TimeoutError(\"query budget already exhausted\")\nconn.set_query_timeout(remaining_ms)","handlingStrategy":"validation","validationCode":"def safe_query_timeout(conn, ms: int) -> None:\n    \"\"\"0 disables the timeout; negative values are invalid.\"\"\"\n    conn.set_query_timeout(max(0, int(ms)))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember 0 means disabled — never -1","With deadline arithmetic, check remaining budget before issuing the statement","Pass get_query_timeout() values through unchanged only if you validated their origin"],"tags":["python","timeout","validation","query-timeout"],"backgroundTag":"invalid-timeout-value","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}