# pyquickbase API reference: Errors This describes version 1.0.0rc13. Other pages: [Quickbase](https://matthew-williams-solutions.github.io/pyquickbase/reference/quickbase.txt), [App](https://matthew-williams-solutions.github.io/pyquickbase/reference/app.txt), [Table](https://matthew-williams-solutions.github.io/pyquickbase/reference/table.txt), [Report](https://matthew-williams-solutions.github.io/pyquickbase/reference/report.txt), [Operation](https://matthew-williams-solutions.github.io/pyquickbase/reference/operation.txt), [SchemaOperation](https://matthew-williams-solutions.github.io/pyquickbase/reference/schema-operation.txt), [Queries](https://matthew-williams-solutions.github.io/pyquickbase/reference/queries.txt), [Records and results](https://matthew-williams-solutions.github.io/pyquickbase/reference/records.txt), [Metadata](https://matthew-williams-solutions.github.io/pyquickbase/reference/metadata.txt), [Schema changes](https://matthew-williams-solutions.github.io/pyquickbase/reference/schema-changes.txt), [Policies](https://matthew-williams-solutions.github.io/pyquickbase/reference/policies.txt), [Rules](https://matthew-williams-solutions.github.io/pyquickbase/reference/rules.txt), [Retries](https://matthew-williams-solutions.github.io/pyquickbase/reference/retries.txt), [Tools for models](https://matthew-williams-solutions.github.io/pyquickbase/reference/tools.txt). Everything the SDK raises derives from [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError). Errors that mean a request wasn't sent come first, then the ones for a request that failed. A timed-out write may still have been applied. The examples below use `tasks`, made as shown here, and `app`, which is `qb.app("bq1234567")`. `Job Tasks` has `Title`, `Status`, `Hours`, `Due Date`, `Code`, which is unique, and `Attachment`. It starts with three records, and each example starts from those again. A live test runs every example with both clients and checks its output. Sync: ```python from pyquickbase import Quickbase with Quickbase( realm="acme", token="your_user_token" ) as qb: tasks = qb.app("bq1234567").table("Job Tasks") ``` Async: ```python from pyquickbase import AsyncQuickbase async with AsyncQuickbase( realm="acme", token="your_user_token" ) as qb: tasks = qb.app("bq1234567").table("Job Tasks") ``` ## The base class For the full picture, see [Handling errors](https://matthew-williams-solutions.github.io/pyquickbase/guides/errors/). ### `QuickbaseError` Base class for every exception this library defines. Sync example: ```python from pyquickbase import QuickbaseError try: tasks.get(1, select=["No Such Field"]) except QuickbaseError as error: print(type(error).__name__) ``` Async example: ```python from pyquickbase import QuickbaseError try: await tasks.get(1, select=["No Such Field"]) except QuickbaseError as error: print(type(error).__name__) ``` Output: ```text UnknownFieldError ``` ## Mistakes caught before sending For the full picture, see [Handling errors](https://matthew-williams-solutions.github.io/pyquickbase/guides/errors/). ### `ConfigurationError` The client was given invalid or missing settings. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import ConfigurationError try: qb.app("not an app ID") except ConfigurationError as error: print(error) ``` Async example: ```python from pyquickbase import ConfigurationError try: qb.app("not an app ID") except ConfigurationError as error: print(error) ``` Output: ```text An app ID contains only letters and numbers. ``` ### `QueryError` A query can't be sent as written, so it wasn't sent to Quickbase. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import QueryError try: tasks.count("{7.ex.'Open'}") except QueryError: print("A lowercase operator was refused") ``` Async example: ```python from pyquickbase import QueryError try: await tasks.count("{7.ex.'Open'}") except QueryError: print("A lowercase operator was refused") ``` Output: ```text A lowercase operator was refused ``` ### `TooManyRecordsError` More records match a summary than its `max_records_scanned` lets it read. None were read. A summary that only counts reads no records, so this is raised only for one that groups, totals, averages, or finds the lowest or highest value. **Inherits from** [`QueryError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QueryError) **Attributes** - **`matched`** `int` How many records match. - **`limit`** `int` The most records the summary may read. Sync example: ```python from pyquickbase import TooManyRecordsError try: tasks.summarize( "Status", sum="Hours", max_records_scanned=1 ) except TooManyRecordsError as error: print(error.matched > error.limit, error.limit) ``` Async example: ```python from pyquickbase import TooManyRecordsError try: await tasks.summarize( "Status", sum="Hours", max_records_scanned=1 ) except TooManyRecordsError as error: print(error.matched > error.limit, error.limit) ``` Output: ```text True 1 ``` ### `ConfirmationError` A change needs the confirmation its preview or plan returned, and this one is missing, expired, or for something else. Nothing was changed. Preview or plan again, and show the person the result. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import ConfirmationError update = tasks.operation("update", require_preview=True) try: update.run( {"records": [{"Record ID#": 1, "Status": "Done"}]} ) except ConfirmationError: print("Preview it first") ``` Async example: ```python from pyquickbase import ConfirmationError update = await tasks.operation("update", require_preview=True) try: await update.run( {"records": [{"Record ID#": 1, "Status": "Done"}]} ) except ConfirmationError: print("Preview it first") ``` Output: ```text Preview it first ``` ### `InvalidValueError` A write can't be sent as written, so it wasn't sent to Quickbase. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import InvalidValueError try: tasks.insert([{"Record ID#": 1, "Title": "Oops"}]) except InvalidValueError: print("Nothing was written") ``` Async example: ```python from pyquickbase import InvalidValueError try: await tasks.insert([{"Record ID#": 1, "Title": "Oops"}]) except InvalidValueError: print("Nothing was written") ``` Output: ```text Nothing was written ``` ### `FileTooLargeError` A file is over a limit on how much of it may be read, so reading stopped. **Inherits from** [`InvalidValueError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#InvalidValueError) **Attributes** - **`limit`** `int` The limit it went over. - **`unit`** `Literal['rows', 'bytes']` What [`limit`](https://matthew-williams-solutions.github.io/pyquickbase/reference/rules/#limit) counts: `rows`, for `max_rows`, or `bytes`, for `max_unzipped_bytes`. Sync example: ```python import io from pyquickbase import FileTooLargeError try: tasks.rows_from_file( io.StringIO("Title\nOne\nTwo\n"), max_rows=1 ) except FileTooLargeError as error: print(error.limit, error.unit) ``` Async example: ```python import io from pyquickbase import FileTooLargeError try: await tasks.rows_from_file( io.StringIO("Title\nOne\nTwo\n"), max_rows=1 ) except FileTooLargeError as error: print(error.limit, error.unit) ``` Output: ```text 1 rows ``` ### `PolicyRefusedError` The client's `policy` doesn't allow this request, so it wasn't sent. The message says what was refused, by name, which rule refused it, and what would allow it, without repeating any values from the request. Quickbase's own permissions still apply to whatever the policy allows. A field the policy hides raises [`UnknownFieldError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#UnknownFieldError) instead, as if it didn't exist. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) **Attributes** - **`decision`** `Any` The [`Decision`](https://matthew-williams-solutions.github.io/pyquickbase/reference/policies/#Decision), with the rule, the reason, and the tables and fields involved. Sync example: ```python from pyquickbase import ( Quickbase, Policy, PolicyRefusedError, ) with Quickbase.from_env( policy=Policy.read_only() ) as qb: tasks = qb.app("bq1234567").table("bqtasks123") try: tasks.insert([{"Title": "Paint walls"}]) except PolicyRefusedError as error: print(error.decision.verb, error.decision.layer) print(error.decision.reason) ``` Async example: ```python from pyquickbase import ( AsyncQuickbase, Policy, PolicyRefusedError, ) async with AsyncQuickbase.from_env( policy=Policy.read_only() ) as qb: tasks = qb.app("bq1234567").table("bqtasks123") try: await tasks.insert([{"Title": "Paint walls"}]) except PolicyRefusedError as error: print(error.decision.verb, error.decision.layer) print(error.decision.reason) ``` Output: ```text insert policy No rule allows it ``` ## Names that don't match For the full picture, see [Handling errors](https://matthew-williams-solutions.github.io/pyquickbase/guides/errors/). ### `UnknownTableError` The app has no table with that name or ID. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import UnknownTableError try: app.table("Job Task").info() except UnknownTableError: print("There's no such table") ``` Async example: ```python from pyquickbase import UnknownTableError try: await app.table("Job Task").info() except UnknownTableError: print("There's no such table") ``` Output: ```text There's no such table ``` ### `UnknownFieldError` The table has no field with that label or ID. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import F, UnknownFieldError try: tasks.count(F("Statuss") == "Open") except UnknownFieldError as error: print(error) ``` Async example: ```python from pyquickbase import F, UnknownFieldError try: await tasks.count(F("Statuss") == "Open") except UnknownFieldError as error: print(error) ``` Output: ```text This table has no field labeled 'Statuss', or this client can't see it. Did you mean 'Status'? ``` ### `UnknownReportError` The table has no report with that name or ID, or several reports share the name. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import UnknownReportError try: tasks.report("No Such Report").info() except UnknownReportError: print("There's no such report") ``` Async example: ```python from pyquickbase import UnknownReportError try: await tasks.report("No Such Report").info() except UnknownReportError: print("There's no such report") ``` Output: ```text There's no such report ``` ### `UnsupportedReportError` The report can't be read as records, such as a summary or chart report. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import UnsupportedReportError try: tasks.report("List All").summary_rows() except UnsupportedReportError: print("That's a table report, so use run()") ``` Async example: ```python from pyquickbase import UnsupportedReportError try: await tasks.report("List All").summary_rows() except UnsupportedReportError: print("That's a table report, so use run()") ``` Output: ```text That's a table report, so use run() ``` ### `SchemaMismatchError` A table doesn't match what the code expects, so nothing was changed. An `ensure_` method found a field that isn't what it was asked for, or the schema changed since a plan was made. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) Sync example: ```python from pyquickbase import SchemaMismatchError try: tasks.ensure_field("Title", "numeric") except SchemaMismatchError: print("Title isn't numeric, and wasn't changed") ``` Async example: ```python from pyquickbase import SchemaMismatchError try: await tasks.ensure_field("Title", "numeric") except SchemaMismatchError: print("Title isn't numeric, and wasn't changed") ``` Output: ```text Title isn't numeric, and wasn't changed ``` ## Writes For the full picture, see [Writing records](https://matthew-williams-solutions.github.io/pyquickbase/guides/writing/). ### `WriteError` Part of a write failed, and the rest may have been applied. When a later batch of a large write fails, `__cause__` holds that batch's own error, such as a [`RateLimitError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#RateLimitError) or [`RequestTimeoutError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#RequestTimeoutError). **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) **Attributes** - **`result`** `Any` A [`WriteResult`](https://matthew-williams-solutions.github.io/pyquickbase/reference/records/#WriteResult) with the records that were written and the rows that failed, when Quickbase reported them. Sync example: ```python from pyquickbase import WriteError try: tasks.insert([{"Title": "Repeat", "Code": "T-1"}]) except WriteError as error: print(error.result.errors[0].reason) ``` Async example: ```python from pyquickbase import WriteError try: await tasks.insert([{"Title": "Repeat", "Code": "T-1"}]) except WriteError as error: print(error.result.errors[0].reason) ``` Output: ```text duplicate ``` ### `WritePermissionError` A write was refused because of the token's role, so nothing in the failed rows changed. Quickbase refuses some writes with a 403, and reports others as row errors in a successful response, depending on the role. Both raise this, so `except PermissionDeniedError` and `except WriteError` each catch it. `result` holds what earlier batches or rows did write. If some rows failed for other reasons as well, you get a plain [`WriteError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#WriteError), whose rows each have a `kind`. **Inherits from** [`WriteError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#WriteError), [`PermissionDeniedError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#PermissionDeniedError) **Attributes** - **`status_code`** `int` 403 for a refused request, and 207 for row errors. ```python class WritePermissionError(WriteError, PermissionDeniedError) ``` ### `SchemaChangeError` A change in a schema plan failed, so the ones after it weren't attempted. Quickbase can't undo the changes before it, so `result` says which were made. Planning the same changes again shows only what's left, as the ones made count as already done. **Inherits from** [`WriteError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#WriteError) **Attributes** - **`result`** `Any` A [`SchemaChangeResult`](https://matthew-williams-solutions.github.io/pyquickbase/reference/schema-changes/#SchemaChangeResult). ```python class SchemaChangeError(WriteError) ``` ## Responses from Quickbase For the full picture, see [Handling errors](https://matthew-williams-solutions.github.io/pyquickbase/guides/errors/). ### `APIError` Quickbase answered with an unsuccessful status code. This is the base of the errors for each status, so it's what you catch for any of them. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) **Attributes** - **`status_code`** `int` The HTTP status. - **`method`** `str` The request's HTTP method. - **`path`** `str` The request's path. - **`message`** `str | None` Quickbase's wording, when it sent any. It can contain HTML, so escape it before showing it in a web page. - **`description`** `str | None` Quickbase's further explanation, when it sent any. - **`request_id`** `str | None` Include this when reporting a problem to Quickbase support. Sync example: ```python from pyquickbase import APIError try: qb.request( "GET", "/tables/bzzzzzzzz", params={"appId": "bq1234567"}, ) except APIError as error: print(error.status_code, error.method) print(error.message) ``` Async example: ```python from pyquickbase import APIError try: await qb.request( "GET", "/tables/bzzzzzzzz", params={"appId": "bq1234567"}, ) except APIError as error: print(error.status_code, error.method) print(error.message) ``` Output: ```text 404 GET Invalid DBID ``` ### `BadRequestError` 400: Quickbase rejected the request as malformed. **Inherits from** [`APIError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#APIError) Sync example: ```python from pyquickbase import BadRequestError try: app.create_table("Job Tasks") except BadRequestError as error: print(error.status_code) ``` Async example: ```python from pyquickbase import BadRequestError try: await app.create_table("Job Tasks") except BadRequestError as error: print(error.status_code) ``` Output: ```text 400 ``` ### `AuthenticationError` 401: the token is invalid, or the app or table doesn't exist or is out of the token's reach. Quickbase gives the same answer for all of these, so this can't say which one happened. **Inherits from** [`APIError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#APIError) Sync example: ```python from pyquickbase import AuthenticationError try: qb.app("bzzzzzzzz").info() except AuthenticationError as error: print(error.status_code) print(error.message) ``` Async example: ```python from pyquickbase import AuthenticationError try: await qb.app("bzzzzzzzz").info() except AuthenticationError as error: print(error.status_code) print(error.message) ``` Output: ```text 401 Access denied ``` ### `PermissionDeniedError` 403: the token's user may not perform this action. **Inherits from** [`APIError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#APIError) ```python class PermissionDeniedError(APIError) ``` ### `NotFoundError` 404: what was asked for doesn't exist. An app that doesn't exist is a 401 instead. **Inherits from** [`APIError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#APIError) Sync example: ```python from pyquickbase import NotFoundError try: tasks.download_file(999, "Attachment") except NotFoundError as error: print(error.status_code) ``` Async example: ```python from pyquickbase import NotFoundError try: await tasks.download_file(999, "Attachment") except NotFoundError as error: print(error.status_code) ``` Output: ```text 404 ``` ### `RateLimitError` 429: retries ran out, or Quickbase asked for a longer wait than the retry policy allows. **Inherits from** [`APIError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#APIError) **Attributes** - **`retry_after`** `float | None` The wait Quickbase asked for, in seconds, if it did. ```python class RateLimitError(APIError) ``` ### `ServerError` 5xx: Quickbase failed to process the request. **Inherits from** [`APIError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#APIError) ```python class ServerError(APIError) ``` ## Connection failures For the full picture, see [Handling errors](https://matthew-williams-solutions.github.io/pyquickbase/guides/errors/). ### `NetworkError` The request failed before a response was received. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) ```python class NetworkError(QuickbaseError) ``` ### `RequestTimeoutError` The request timed out. A timed-out write may still have been applied. **Inherits from** [`NetworkError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#NetworkError) Sync example: ```python from pyquickbase import ( Quickbase, NetworkError, RetryPolicy, ) no_retries = RetryPolicy(max_retries=0) with Quickbase.from_env( timeout=0.0001, retry=no_retries ) as qb: try: qb.app("bq1234567").tables() except NetworkError as error: print(type(error).__name__) ``` Async example: ```python from pyquickbase import ( AsyncQuickbase, NetworkError, RetryPolicy, ) no_retries = RetryPolicy(max_retries=0) async with AsyncQuickbase.from_env( timeout=0.0001, retry=no_retries ) as qb: try: await qb.app("bq1234567").tables() except NetworkError as error: print(type(error).__name__) ``` Output: ```text RequestTimeoutError ``` ### `InvalidResponseError` Quickbase reported success, but the response body wasn't in the expected format. **Inherits from** [`QuickbaseError`](https://matthew-williams-solutions.github.io/pyquickbase/reference/errors/#QuickbaseError) ```python class InvalidResponseError(QuickbaseError) ```