airbyte.exceptions

All exceptions used in the PyAirbyte.

This design is modeled after structlog's exceptions, in that we bias towards auto-generated property prints rather than sentence-like string concatenation.

E.g. Instead of this:

Subprocess failed with exit code '1'

We do this:

Subprocess failed. (exit_code=1)

The benefit of this approach is that we can easily support structured logging, and we can easily add new properties to exceptions without having to update all the places where they are raised. We can also support any arbitrary number of properties in exceptions, without spending time on building sentence-like string constructions with optional inputs.

In addition, the following principles are applied for exception class design:

  • All exceptions inherit from a common base class.
  • All exceptions have a message attribute.
  • The first line of the docstring is used as the default message.
  • The default message can be overridden by explicitly setting the message attribute.
  • Exceptions may optionally have a guidance attribute.
  • Exceptions may optionally have a help_url attribute.
  • Rendering is automatically handled by the base class.
  • Any helpful context not defined by the exception class can be passed in the context dict arg.
  • Within reason, avoid sending PII to the exception constructor.
  • Exceptions are dataclasses, so they can be instantiated with keyword arguments.
  • Use the 'from' syntax to chain exceptions when it is helpful to do so. E.g. raise AirbyteConnectorNotFoundError(...) from FileNotFoundError(connector_path)
  • Any exception that adds a new property should also be decorated as @dataclass.
  1# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
  2
  3"""All exceptions used in the PyAirbyte.
  4
  5This design is modeled after structlog's exceptions, in that we bias towards auto-generated
  6property prints rather than sentence-like string concatenation.
  7
  8E.g. Instead of this:
  9
 10> `Subprocess failed with exit code '1'`
 11
 12We do this:
 13
 14> `Subprocess failed. (exit_code=1)`
 15
 16The benefit of this approach is that we can easily support structured logging, and we can
 17easily add new properties to exceptions without having to update all the places where they
 18are raised. We can also support any arbitrary number of properties in exceptions, without spending
 19time on building sentence-like string constructions with optional inputs.
 20
 21
 22In addition, the following principles are applied for exception class design:
 23
 24- All exceptions inherit from a common base class.
 25- All exceptions have a message attribute.
 26- The first line of the docstring is used as the default message.
 27- The default message can be overridden by explicitly setting the message attribute.
 28- Exceptions may optionally have a guidance attribute.
 29- Exceptions may optionally have a help_url attribute.
 30- Rendering is automatically handled by the base class.
 31- Any helpful context not defined by the exception class can be passed in the `context` dict arg.
 32- Within reason, avoid sending PII to the exception constructor.
 33- Exceptions are dataclasses, so they can be instantiated with keyword arguments.
 34- Use the 'from' syntax to chain exceptions when it is helpful to do so.
 35  E.g. `raise AirbyteConnectorNotFoundError(...) from FileNotFoundError(connector_path)`
 36- Any exception that adds a new property should also be decorated as `@dataclass`.
 37"""
 38
 39from __future__ import annotations
 40
 41import logging
 42from dataclasses import dataclass
 43from pathlib import Path
 44from textwrap import indent
 45from typing import TYPE_CHECKING, Any
 46
 47
 48if TYPE_CHECKING:
 49    from airbyte._util.api_duck_types import AirbyteApiResponseDuckType
 50    from airbyte.cloud.workspaces import CloudWorkspace
 51
 52
 53NEW_ISSUE_URL = "https://github.com/airbytehq/airbyte/issues/new/choose"
 54DOCS_URL_BASE = "https://airbytehq.github.io/PyAirbyte"
 55DOCS_URL = f"{DOCS_URL_BASE}/airbyte.html"
 56
 57VERTICAL_SEPARATOR = "\n" + "-" * 60
 58
 59
 60# Base error class
 61
 62
 63@dataclass
 64class PyAirbyteError(Exception):
 65    """Base class for exceptions in Airbyte."""
 66
 67    guidance: str | None = None
 68    help_url: str | None = None
 69    log_text: str | list[str] | None = None
 70    log_file: Path | None = None
 71    context: dict[str, Any] | None = None
 72    message: str | None = None
 73    original_exception: Exception | None = None
 74
 75    def get_message(self) -> str:
 76        """Return the best description for the exception.
 77
 78        We resolve the following in order:
 79        1. The message sent to the exception constructor (if provided).
 80        2. The first line of the class's docstring.
 81        """
 82        if self.message:
 83            return self.message
 84
 85        return self.__doc__.split("\n")[0] if self.__doc__ else ""
 86
 87    def __str__(self) -> str:
 88        """Return a string representation of the exception."""
 89        special_properties = [
 90            "message",
 91            "guidance",
 92            "help_url",
 93            "log_text",
 94            "context",
 95            "log_file",
 96            "original_exception",
 97        ]
 98        display_properties = {
 99            k: v
100            for k, v in self.__dict__.items()
101            if k not in special_properties and not k.startswith("_") and v is not None
102        }
103        display_properties.update(self.context or {})
104        context_str = "\n    ".join(
105            f"{str(k).replace('_', ' ').title()}: {v!r}" for k, v in display_properties.items()
106        )
107        exception_str = (
108            f"{self.get_message()} ({self.__class__.__name__})"
109            + VERTICAL_SEPARATOR
110            + f"\n{self.__class__.__name__}: {self.get_message()}"
111        )
112
113        if self.guidance:
114            exception_str += f"\n    {self.guidance}"
115
116        if self.help_url:
117            exception_str += f"\n    More info: {self.help_url}"
118
119        if context_str:
120            exception_str += "\n    " + context_str
121
122        if self.log_file:
123            exception_str += f"\n    Log file: {self.log_file.absolute()!s}"
124
125        if self.log_text:
126            if isinstance(self.log_text, list):
127                self.log_text = "\n".join(self.log_text)
128
129            exception_str += f"\n    Log output: \n    {indent(self.log_text, '    ')}"
130
131        if self.original_exception:
132            exception_str += VERTICAL_SEPARATOR + f"\nCaused by: {self.original_exception!s}"
133
134        return exception_str
135
136    def __repr__(self) -> str:
137        """Return a string representation of the exception."""
138        class_name = self.__class__.__name__
139        properties_str = ", ".join(
140            f"{k}={v!r}" for k, v in self.__dict__.items() if not k.startswith("_")
141        )
142        return f"{class_name}({properties_str})"
143
144    def safe_logging_dict(self) -> dict[str, Any]:
145        """Return a dictionary of the exception's properties which is safe for logging.
146
147        We avoid any properties which could potentially contain PII.
148        """
149        result = {
150            # The class name is safe to log:
151            "class": self.__class__.__name__,
152            # We discourage interpolated strings in 'message' so that this should never contain PII:
153            "message": self.get_message(),
154        }
155        safe_attrs = ["connector_name", "stream_name", "violation", "exit_code"]
156        for attr in safe_attrs:
157            if hasattr(self, attr):
158                result[attr] = getattr(self, attr)
159
160        return result
161
162
163# PyAirbyte Internal Errors (these are probably bugs)
164
165
166@dataclass
167class PyAirbyteInternalError(PyAirbyteError):
168    """An internal error occurred in PyAirbyte."""
169
170    guidance = "Please consider reporting this error to the Airbyte team."
171    help_url = NEW_ISSUE_URL
172
173
174# PyAirbyte Input Errors (replaces ValueError for user input)
175
176
177@dataclass
178class PyAirbyteInputError(PyAirbyteError, ValueError):
179    """The input provided to PyAirbyte did not match expected validation rules.
180
181    This inherits from ValueError so that it can be used as a drop-in replacement for
182    ValueError in the PyAirbyte API.
183    """
184
185    guidance = "Please check the provided value and try again."
186    help_url = DOCS_URL
187    input_value: str | None = None
188
189
190@dataclass
191class PyAirbyteNoStreamsSelectedError(PyAirbyteInputError):
192    """No streams were selected for the source."""
193
194    guidance = (
195        "Please call `select_streams()` to select at least one stream from the list provided. "
196        "You can also call `select_all_streams()` to select all available streams for this source."
197    )
198    connector_name: str | None = None
199    available_streams: list[str] | None = None
200
201
202# Normalization Errors
203
204
205@dataclass
206class PyAirbyteNameNormalizationError(PyAirbyteError, ValueError):
207    """Error occurred while normalizing a table or column name."""
208
209    guidance = (
210        "Please consider renaming the source object if possible, or "
211        "raise an issue in GitHub if not."
212    )
213    help_url = NEW_ISSUE_URL
214
215    raw_name: str | None = None
216    normalization_result: str | None = None
217
218
219# PyAirbyte Cache Errors
220
221
222class PyAirbyteCacheError(PyAirbyteError):
223    """Error occurred while accessing the cache."""
224
225
226@dataclass
227class PyAirbyteCacheTableValidationError(PyAirbyteCacheError):
228    """Cache table validation failed."""
229
230    violation: str | None = None
231
232
233@dataclass
234class AirbyteConnectorConfigurationMissingError(PyAirbyteCacheError):
235    """Connector is missing configuration."""
236
237    connector_name: str | None = None
238
239
240# Subprocess Errors
241
242
243@dataclass
244class AirbyteSubprocessError(PyAirbyteError):
245    """Error when running subprocess."""
246
247    run_args: list[str] | None = None
248
249
250@dataclass
251class AirbyteSubprocessFailedError(AirbyteSubprocessError):
252    """Subprocess failed."""
253
254    exit_code: int | None = None
255
256
257# Connector Registry Errors
258
259
260class AirbyteConnectorRegistryError(PyAirbyteError):
261    """Error when accessing the connector registry."""
262
263
264@dataclass
265class AirbyteConnectorNotRegisteredError(AirbyteConnectorRegistryError):
266    """Connector not found in registry."""
267
268    connector_name: str | None = None
269    guidance = (
270        "Please double check the connector name. "
271        "Alternatively, you can provide an explicit connector install method to `get_source()`: "
272        "`pip_url`, `local_executable`, `docker_image`, or `source_manifest`."
273    )
274    help_url = DOCS_URL_BASE + "/airbyte/sources/util.html#get_source"
275
276
277@dataclass
278class AirbyteConnectorNotPyPiPublishedError(AirbyteConnectorRegistryError):
279    """Connector found, but not published to PyPI."""
280
281    connector_name: str | None = None
282    guidance = "This likely means that the connector is not ready for use with PyAirbyte."
283
284
285# Connector Errors
286
287
288@dataclass
289class AirbyteConnectorError(PyAirbyteError):
290    """Error when running the connector."""
291
292    connector_name: str | None = None
293
294    def __post_init__(self) -> None:
295        """Set the log file path for the connector."""
296        self.log_file = self._get_log_file()
297        if not self.guidance and self.log_file:
298            self.guidance = "Please review the log file for more information."
299
300    def _get_log_file(self) -> Path | None:
301        """Return the log file path for the connector."""
302        if self.connector_name:
303            logger = logging.getLogger(f"airbyte.{self.connector_name}")
304
305            log_paths: list[Path] = [
306                Path(handler.baseFilename).absolute()
307                for handler in logger.handlers
308                if isinstance(handler, logging.FileHandler)
309            ]
310
311            if log_paths:
312                return log_paths[0]
313
314        return None
315
316
317class AirbyteConnectorExecutableNotFoundError(AirbyteConnectorError):
318    """Connector executable not found."""
319
320
321class AirbyteConnectorInstallationError(AirbyteConnectorError):
322    """Error when installing the connector."""
323
324
325class AirbyteConnectorReadError(AirbyteConnectorError):
326    """Error when reading from the connector."""
327
328
329class AirbyteConnectorWriteError(AirbyteConnectorError):
330    """Error when writing to the connector."""
331
332
333class AirbyteConnectorSpecFailedError(AirbyteConnectorError):
334    """Error when getting spec from the connector."""
335
336
337class AirbyteConnectorDiscoverFailedError(AirbyteConnectorError):
338    """Error when running discovery on the connector."""
339
340
341class AirbyteNoDataFromConnectorError(AirbyteConnectorError):
342    """No data was provided from the connector."""
343
344
345class AirbyteConnectorMissingCatalogError(AirbyteConnectorError):
346    """Connector did not return a catalog."""
347
348
349class AirbyteConnectorMissingSpecError(AirbyteConnectorError):
350    """Connector did not return a spec."""
351
352
353class AirbyteConnectorValidationFailedError(AirbyteConnectorError):
354    """Connector config validation failed."""
355
356    guidance = (
357        "Please double-check your config and review the validation errors for more information."
358    )
359
360
361class AirbyteConnectorCheckFailedError(AirbyteConnectorError):
362    """Connector check failed."""
363
364    guidance = (
365        "Please double-check your config or review the connector's logs for more information."
366    )
367
368
369@dataclass
370class AirbyteConnectorFailedError(AirbyteConnectorError):
371    """Connector failed."""
372
373    exit_code: int | None = None
374
375
376@dataclass
377class AirbyteStreamNotFoundError(AirbyteConnectorError):
378    """Connector stream not found."""
379
380    stream_name: str | None = None
381    available_streams: list[str] | None = None
382
383
384@dataclass
385class AirbyteStateNotFoundError(AirbyteConnectorError, KeyError):
386    """State entry not found."""
387
388    stream_name: str | None = None
389    available_streams: list[str] | None = None
390
391
392@dataclass
393class PyAirbyteSecretNotFoundError(PyAirbyteError):
394    """Secret not found."""
395
396    guidance = "Please ensure that the secret is set."
397    help_url = (
398        "https://docs.airbyte.com/using-airbyte/airbyte-lib/getting-started#secrets-management"
399    )
400
401    secret_name: str | None = None
402    sources: list[str] | None = None
403
404
405# Airbyte API Errors
406
407
408@dataclass
409class AirbyteError(PyAirbyteError):
410    """An error occurred while communicating with the hosted Airbyte instance."""
411
412    response: AirbyteApiResponseDuckType | None = None
413    """The API response from the failed request."""
414
415    workspace: CloudWorkspace | None = None
416    """The workspace where the error occurred."""
417
418    @property
419    def workspace_url(self) -> str | None:
420        """The URL to the workspace where the error occurred."""
421        if self.workspace:
422            return self.workspace.workspace_url
423
424        return None
425
426
427@dataclass
428class AirbyteConnectionError(AirbyteError):
429    """An connection error occurred while communicating with the hosted Airbyte instance."""
430
431    connection_id: str | None = None
432    """The connection ID where the error occurred."""
433
434    job_id: str | None = None
435    """The job ID where the error occurred (if applicable)."""
436
437    job_status: str | None = None
438    """The latest status of the job where the error occurred (if applicable)."""
439
440    @property
441    def connection_url(self) -> str | None:
442        """The URL to the connection where the error occurred."""
443        if self.workspace_url and self.connection_id:
444            return f"{self.workspace_url}/connections/{self.connection_id}"
445
446        return None
447
448    @property
449    def job_history_url(self) -> str | None:
450        """The URL to the job history where the error occurred."""
451        if self.connection_url:
452            return f"{self.connection_url}/job-history"
453
454        return None
455
456    @property
457    def job_url(self) -> str | None:
458        """The URL to the job where the error occurred."""
459        if self.job_history_url and self.job_id:
460            return f"{self.job_history_url}#{self.job_id}::0"
461
462        return None
463
464
465@dataclass
466class AirbyteConnectionSyncError(AirbyteConnectionError):
467    """An error occurred while executing the remote Airbyte job."""
468
469
470@dataclass
471class AirbyteConnectionSyncTimeoutError(AirbyteConnectionSyncError):
472    """An timeout occurred while waiting for the remote Airbyte job to complete."""
473
474    timeout: int | None = None
475    """The timeout in seconds that was reached."""
476
477
478# Airbyte Resource Errors (General)
479
480
481@dataclass
482class AirbyteMissingResourceError(AirbyteError):
483    """Remote Airbyte resources does not exist."""
484
485    resource_type: str | None = None
486    resource_name_or_id: str | None = None
487
488
489@dataclass
490class AirbyteMultipleResourcesError(AirbyteError):
491    """Could not locate the resource because multiple matching resources were found."""
492
493    resource_type: str | None = None
494    resource_name_or_id: str | None = None
495
496
497# Custom Warnings
498
499
500class AirbyteExperimentalFeatureWarning(FutureWarning):
501    """Warning whenever using experimental features in PyAirbyte."""
502
503
504# PyAirbyte Warnings
505
506
507class PyAirbyteWarning(Warning):
508    """General warnings from PyAirbyte."""
509
510
511class PyAirbyteDataLossWarning(PyAirbyteWarning):
512    """Warning for potential data loss.
513
514    Users can ignore this warning by running:
515    > warnings.filterwarnings("ignore", category="airbyte.exceptions.PyAirbyteDataLossWarning")
516    """
NEW_ISSUE_URL = 'https://github.com/airbytehq/airbyte/issues/new/choose'
DOCS_URL_BASE = 'https://airbytehq.github.io/PyAirbyte'
DOCS_URL = 'https://airbytehq.github.io/PyAirbyte/airbyte.html'
VERTICAL_SEPARATOR = '\n------------------------------------------------------------'
@dataclass
class PyAirbyteError(builtins.Exception):
 64@dataclass
 65class PyAirbyteError(Exception):
 66    """Base class for exceptions in Airbyte."""
 67
 68    guidance: str | None = None
 69    help_url: str | None = None
 70    log_text: str | list[str] | None = None
 71    log_file: Path | None = None
 72    context: dict[str, Any] | None = None
 73    message: str | None = None
 74    original_exception: Exception | None = None
 75
 76    def get_message(self) -> str:
 77        """Return the best description for the exception.
 78
 79        We resolve the following in order:
 80        1. The message sent to the exception constructor (if provided).
 81        2. The first line of the class's docstring.
 82        """
 83        if self.message:
 84            return self.message
 85
 86        return self.__doc__.split("\n")[0] if self.__doc__ else ""
 87
 88    def __str__(self) -> str:
 89        """Return a string representation of the exception."""
 90        special_properties = [
 91            "message",
 92            "guidance",
 93            "help_url",
 94            "log_text",
 95            "context",
 96            "log_file",
 97            "original_exception",
 98        ]
 99        display_properties = {
100            k: v
101            for k, v in self.__dict__.items()
102            if k not in special_properties and not k.startswith("_") and v is not None
103        }
104        display_properties.update(self.context or {})
105        context_str = "\n    ".join(
106            f"{str(k).replace('_', ' ').title()}: {v!r}" for k, v in display_properties.items()
107        )
108        exception_str = (
109            f"{self.get_message()} ({self.__class__.__name__})"
110            + VERTICAL_SEPARATOR
111            + f"\n{self.__class__.__name__}: {self.get_message()}"
112        )
113
114        if self.guidance:
115            exception_str += f"\n    {self.guidance}"
116
117        if self.help_url:
118            exception_str += f"\n    More info: {self.help_url}"
119
120        if context_str:
121            exception_str += "\n    " + context_str
122
123        if self.log_file:
124            exception_str += f"\n    Log file: {self.log_file.absolute()!s}"
125
126        if self.log_text:
127            if isinstance(self.log_text, list):
128                self.log_text = "\n".join(self.log_text)
129
130            exception_str += f"\n    Log output: \n    {indent(self.log_text, '    ')}"
131
132        if self.original_exception:
133            exception_str += VERTICAL_SEPARATOR + f"\nCaused by: {self.original_exception!s}"
134
135        return exception_str
136
137    def __repr__(self) -> str:
138        """Return a string representation of the exception."""
139        class_name = self.__class__.__name__
140        properties_str = ", ".join(
141            f"{k}={v!r}" for k, v in self.__dict__.items() if not k.startswith("_")
142        )
143        return f"{class_name}({properties_str})"
144
145    def safe_logging_dict(self) -> dict[str, Any]:
146        """Return a dictionary of the exception's properties which is safe for logging.
147
148        We avoid any properties which could potentially contain PII.
149        """
150        result = {
151            # The class name is safe to log:
152            "class": self.__class__.__name__,
153            # We discourage interpolated strings in 'message' so that this should never contain PII:
154            "message": self.get_message(),
155        }
156        safe_attrs = ["connector_name", "stream_name", "violation", "exit_code"]
157        for attr in safe_attrs:
158            if hasattr(self, attr):
159                result[attr] = getattr(self, attr)
160
161        return result

Base class for exceptions in Airbyte.

PyAirbyteError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None)
guidance: str | None = None
help_url: str | None = None
log_text: str | list[str] | None = None
log_file: pathlib.Path | None = None
context: dict[str, typing.Any] | None = None
message: str | None = None
original_exception: Exception | None = None
def get_message(self) -> str:
76    def get_message(self) -> str:
77        """Return the best description for the exception.
78
79        We resolve the following in order:
80        1. The message sent to the exception constructor (if provided).
81        2. The first line of the class's docstring.
82        """
83        if self.message:
84            return self.message
85
86        return self.__doc__.split("\n")[0] if self.__doc__ else ""

Return the best description for the exception.

We resolve the following in order:

  1. The message sent to the exception constructor (if provided).
  2. The first line of the class's docstring.
def safe_logging_dict(self) -> dict[str, typing.Any]:
145    def safe_logging_dict(self) -> dict[str, Any]:
146        """Return a dictionary of the exception's properties which is safe for logging.
147
148        We avoid any properties which could potentially contain PII.
149        """
150        result = {
151            # The class name is safe to log:
152            "class": self.__class__.__name__,
153            # We discourage interpolated strings in 'message' so that this should never contain PII:
154            "message": self.get_message(),
155        }
156        safe_attrs = ["connector_name", "stream_name", "violation", "exit_code"]
157        for attr in safe_attrs:
158            if hasattr(self, attr):
159                result[attr] = getattr(self, attr)
160
161        return result

Return a dictionary of the exception's properties which is safe for logging.

We avoid any properties which could potentially contain PII.

Inherited Members
builtins.BaseException
with_traceback
args
@dataclass
class PyAirbyteInternalError(PyAirbyteError):
167@dataclass
168class PyAirbyteInternalError(PyAirbyteError):
169    """An internal error occurred in PyAirbyte."""
170
171    guidance = "Please consider reporting this error to the Airbyte team."
172    help_url = NEW_ISSUE_URL

An internal error occurred in PyAirbyte.

PyAirbyteInternalError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None)
guidance = 'Please consider reporting this error to the Airbyte team.'
help_url = 'https://github.com/airbytehq/airbyte/issues/new/choose'
Inherited Members
PyAirbyteError
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class PyAirbyteInputError(PyAirbyteError, builtins.ValueError):
178@dataclass
179class PyAirbyteInputError(PyAirbyteError, ValueError):
180    """The input provided to PyAirbyte did not match expected validation rules.
181
182    This inherits from ValueError so that it can be used as a drop-in replacement for
183    ValueError in the PyAirbyte API.
184    """
185
186    guidance = "Please check the provided value and try again."
187    help_url = DOCS_URL
188    input_value: str | None = None

The input provided to PyAirbyte did not match expected validation rules.

This inherits from ValueError so that it can be used as a drop-in replacement for ValueError in the PyAirbyte API.

PyAirbyteInputError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, input_value: str | None = None)
guidance = 'Please check the provided value and try again.'
help_url = 'https://airbytehq.github.io/PyAirbyte/airbyte.html'
input_value: str | None = None
Inherited Members
PyAirbyteError
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class PyAirbyteNoStreamsSelectedError(PyAirbyteInputError):
191@dataclass
192class PyAirbyteNoStreamsSelectedError(PyAirbyteInputError):
193    """No streams were selected for the source."""
194
195    guidance = (
196        "Please call `select_streams()` to select at least one stream from the list provided. "
197        "You can also call `select_all_streams()` to select all available streams for this source."
198    )
199    connector_name: str | None = None
200    available_streams: list[str] | None = None

No streams were selected for the source.

PyAirbyteNoStreamsSelectedError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, input_value: str | None = None, connector_name: str | None = None, available_streams: list[str] | None = None)
guidance = 'Please call `select_streams()` to select at least one stream from the list provided. You can also call `select_all_streams()` to select all available streams for this source.'
connector_name: str | None = None
available_streams: list[str] | None = None
@dataclass
class PyAirbyteNameNormalizationError(PyAirbyteError, builtins.ValueError):
206@dataclass
207class PyAirbyteNameNormalizationError(PyAirbyteError, ValueError):
208    """Error occurred while normalizing a table or column name."""
209
210    guidance = (
211        "Please consider renaming the source object if possible, or "
212        "raise an issue in GitHub if not."
213    )
214    help_url = NEW_ISSUE_URL
215
216    raw_name: str | None = None
217    normalization_result: str | None = None

Error occurred while normalizing a table or column name.

PyAirbyteNameNormalizationError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, raw_name: str | None = None, normalization_result: str | None = None)
guidance = 'Please consider renaming the source object if possible, or raise an issue in GitHub if not.'
help_url = 'https://github.com/airbytehq/airbyte/issues/new/choose'
raw_name: str | None = None
normalization_result: str | None = None
Inherited Members
PyAirbyteError
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
class PyAirbyteCacheError(PyAirbyteError):
223class PyAirbyteCacheError(PyAirbyteError):
224    """Error occurred while accessing the cache."""

Error occurred while accessing the cache.

@dataclass
class PyAirbyteCacheTableValidationError(PyAirbyteCacheError):
227@dataclass
228class PyAirbyteCacheTableValidationError(PyAirbyteCacheError):
229    """Cache table validation failed."""
230
231    violation: str | None = None

Cache table validation failed.

PyAirbyteCacheTableValidationError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, violation: str | None = None)
violation: str | None = None
Inherited Members
PyAirbyteError
guidance
help_url
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteConnectorConfigurationMissingError(PyAirbyteCacheError):
234@dataclass
235class AirbyteConnectorConfigurationMissingError(PyAirbyteCacheError):
236    """Connector is missing configuration."""
237
238    connector_name: str | None = None

Connector is missing configuration.

AirbyteConnectorConfigurationMissingError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None)
connector_name: str | None = None
Inherited Members
PyAirbyteError
guidance
help_url
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteSubprocessError(PyAirbyteError):
244@dataclass
245class AirbyteSubprocessError(PyAirbyteError):
246    """Error when running subprocess."""
247
248    run_args: list[str] | None = None

Error when running subprocess.

AirbyteSubprocessError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, run_args: list[str] | None = None)
run_args: list[str] | None = None
Inherited Members
PyAirbyteError
guidance
help_url
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteSubprocessFailedError(AirbyteSubprocessError):
251@dataclass
252class AirbyteSubprocessFailedError(AirbyteSubprocessError):
253    """Subprocess failed."""
254
255    exit_code: int | None = None

Subprocess failed.

AirbyteSubprocessFailedError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, run_args: list[str] | None = None, exit_code: int | None = None)
exit_code: int | None = None
class AirbyteConnectorRegistryError(PyAirbyteError):
261class AirbyteConnectorRegistryError(PyAirbyteError):
262    """Error when accessing the connector registry."""

Error when accessing the connector registry.

@dataclass
class AirbyteConnectorNotRegisteredError(AirbyteConnectorRegistryError):
265@dataclass
266class AirbyteConnectorNotRegisteredError(AirbyteConnectorRegistryError):
267    """Connector not found in registry."""
268
269    connector_name: str | None = None
270    guidance = (
271        "Please double check the connector name. "
272        "Alternatively, you can provide an explicit connector install method to `get_source()`: "
273        "`pip_url`, `local_executable`, `docker_image`, or `source_manifest`."
274    )
275    help_url = DOCS_URL_BASE + "/airbyte/sources/util.html#get_source"

Connector not found in registry.

AirbyteConnectorNotRegisteredError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None)
connector_name: str | None = None
guidance = 'Please double check the connector name. Alternatively, you can provide an explicit connector install method to `get_source()`: `pip_url`, `local_executable`, `docker_image`, or `source_manifest`.'
help_url = 'https://airbytehq.github.io/PyAirbyte/airbyte/sources/util.html#get_source'
Inherited Members
PyAirbyteError
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteConnectorNotPyPiPublishedError(AirbyteConnectorRegistryError):
278@dataclass
279class AirbyteConnectorNotPyPiPublishedError(AirbyteConnectorRegistryError):
280    """Connector found, but not published to PyPI."""
281
282    connector_name: str | None = None
283    guidance = "This likely means that the connector is not ready for use with PyAirbyte."

Connector found, but not published to PyPI.

AirbyteConnectorNotPyPiPublishedError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None)
connector_name: str | None = None
guidance = 'This likely means that the connector is not ready for use with PyAirbyte.'
Inherited Members
PyAirbyteError
help_url
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteConnectorError(PyAirbyteError):
289@dataclass
290class AirbyteConnectorError(PyAirbyteError):
291    """Error when running the connector."""
292
293    connector_name: str | None = None
294
295    def __post_init__(self) -> None:
296        """Set the log file path for the connector."""
297        self.log_file = self._get_log_file()
298        if not self.guidance and self.log_file:
299            self.guidance = "Please review the log file for more information."
300
301    def _get_log_file(self) -> Path | None:
302        """Return the log file path for the connector."""
303        if self.connector_name:
304            logger = logging.getLogger(f"airbyte.{self.connector_name}")
305
306            log_paths: list[Path] = [
307                Path(handler.baseFilename).absolute()
308                for handler in logger.handlers
309                if isinstance(handler, logging.FileHandler)
310            ]
311
312            if log_paths:
313                return log_paths[0]
314
315        return None

Error when running the connector.

AirbyteConnectorError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None)
connector_name: str | None = None
Inherited Members
PyAirbyteError
guidance
help_url
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
class AirbyteConnectorExecutableNotFoundError(AirbyteConnectorError):
318class AirbyteConnectorExecutableNotFoundError(AirbyteConnectorError):
319    """Connector executable not found."""

Connector executable not found.

class AirbyteConnectorInstallationError(AirbyteConnectorError):
322class AirbyteConnectorInstallationError(AirbyteConnectorError):
323    """Error when installing the connector."""

Error when installing the connector.

class AirbyteConnectorReadError(AirbyteConnectorError):
326class AirbyteConnectorReadError(AirbyteConnectorError):
327    """Error when reading from the connector."""

Error when reading from the connector.

class AirbyteConnectorWriteError(AirbyteConnectorError):
330class AirbyteConnectorWriteError(AirbyteConnectorError):
331    """Error when writing to the connector."""

Error when writing to the connector.

class AirbyteConnectorSpecFailedError(AirbyteConnectorError):
334class AirbyteConnectorSpecFailedError(AirbyteConnectorError):
335    """Error when getting spec from the connector."""

Error when getting spec from the connector.

class AirbyteConnectorDiscoverFailedError(AirbyteConnectorError):
338class AirbyteConnectorDiscoverFailedError(AirbyteConnectorError):
339    """Error when running discovery on the connector."""

Error when running discovery on the connector.

class AirbyteNoDataFromConnectorError(AirbyteConnectorError):
342class AirbyteNoDataFromConnectorError(AirbyteConnectorError):
343    """No data was provided from the connector."""

No data was provided from the connector.

class AirbyteConnectorMissingCatalogError(AirbyteConnectorError):
346class AirbyteConnectorMissingCatalogError(AirbyteConnectorError):
347    """Connector did not return a catalog."""

Connector did not return a catalog.

class AirbyteConnectorMissingSpecError(AirbyteConnectorError):
350class AirbyteConnectorMissingSpecError(AirbyteConnectorError):
351    """Connector did not return a spec."""

Connector did not return a spec.

class AirbyteConnectorValidationFailedError(AirbyteConnectorError):
354class AirbyteConnectorValidationFailedError(AirbyteConnectorError):
355    """Connector config validation failed."""
356
357    guidance = (
358        "Please double-check your config and review the validation errors for more information."
359    )

Connector config validation failed.

guidance = 'Please double-check your config and review the validation errors for more information.'
class AirbyteConnectorCheckFailedError(AirbyteConnectorError):
362class AirbyteConnectorCheckFailedError(AirbyteConnectorError):
363    """Connector check failed."""
364
365    guidance = (
366        "Please double-check your config or review the connector's logs for more information."
367    )

Connector check failed.

guidance = "Please double-check your config or review the connector's logs for more information."
@dataclass
class AirbyteConnectorFailedError(AirbyteConnectorError):
370@dataclass
371class AirbyteConnectorFailedError(AirbyteConnectorError):
372    """Connector failed."""
373
374    exit_code: int | None = None

Connector failed.

AirbyteConnectorFailedError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None, exit_code: int | None = None)
exit_code: int | None = None
@dataclass
class AirbyteStreamNotFoundError(AirbyteConnectorError):
377@dataclass
378class AirbyteStreamNotFoundError(AirbyteConnectorError):
379    """Connector stream not found."""
380
381    stream_name: str | None = None
382    available_streams: list[str] | None = None

Connector stream not found.

AirbyteStreamNotFoundError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None, stream_name: str | None = None, available_streams: list[str] | None = None)
stream_name: str | None = None
available_streams: list[str] | None = None
@dataclass
class AirbyteStateNotFoundError(AirbyteConnectorError, builtins.KeyError):
385@dataclass
386class AirbyteStateNotFoundError(AirbyteConnectorError, KeyError):
387    """State entry not found."""
388
389    stream_name: str | None = None
390    available_streams: list[str] | None = None

State entry not found.

AirbyteStateNotFoundError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, connector_name: str | None = None, stream_name: str | None = None, available_streams: list[str] | None = None)
stream_name: str | None = None
available_streams: list[str] | None = None
@dataclass
class PyAirbyteSecretNotFoundError(PyAirbyteError):
393@dataclass
394class PyAirbyteSecretNotFoundError(PyAirbyteError):
395    """Secret not found."""
396
397    guidance = "Please ensure that the secret is set."
398    help_url = (
399        "https://docs.airbyte.com/using-airbyte/airbyte-lib/getting-started#secrets-management"
400    )
401
402    secret_name: str | None = None
403    sources: list[str] | None = None

Secret not found.

PyAirbyteSecretNotFoundError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, secret_name: str | None = None, sources: list[str] | None = None)
guidance = 'Please ensure that the secret is set.'
help_url = 'https://docs.airbyte.com/using-airbyte/airbyte-lib/getting-started#secrets-management'
secret_name: str | None = None
sources: list[str] | None = None
Inherited Members
PyAirbyteError
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteError(PyAirbyteError):
409@dataclass
410class AirbyteError(PyAirbyteError):
411    """An error occurred while communicating with the hosted Airbyte instance."""
412
413    response: AirbyteApiResponseDuckType | None = None
414    """The API response from the failed request."""
415
416    workspace: CloudWorkspace | None = None
417    """The workspace where the error occurred."""
418
419    @property
420    def workspace_url(self) -> str | None:
421        """The URL to the workspace where the error occurred."""
422        if self.workspace:
423            return self.workspace.workspace_url
424
425        return None

An error occurred while communicating with the hosted Airbyte instance.

AirbyteError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None, workspace: airbyte.cloud.CloudWorkspace | None = None)
response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None

The API response from the failed request.

workspace: airbyte.cloud.CloudWorkspace | None = None

The workspace where the error occurred.

workspace_url: str | None
419    @property
420    def workspace_url(self) -> str | None:
421        """The URL to the workspace where the error occurred."""
422        if self.workspace:
423            return self.workspace.workspace_url
424
425        return None

The URL to the workspace where the error occurred.

Inherited Members
PyAirbyteError
guidance
help_url
log_text
log_file
context
message
original_exception
get_message
safe_logging_dict
builtins.BaseException
with_traceback
args
@dataclass
class AirbyteConnectionError(AirbyteError):
428@dataclass
429class AirbyteConnectionError(AirbyteError):
430    """An connection error occurred while communicating with the hosted Airbyte instance."""
431
432    connection_id: str | None = None
433    """The connection ID where the error occurred."""
434
435    job_id: str | None = None
436    """The job ID where the error occurred (if applicable)."""
437
438    job_status: str | None = None
439    """The latest status of the job where the error occurred (if applicable)."""
440
441    @property
442    def connection_url(self) -> str | None:
443        """The URL to the connection where the error occurred."""
444        if self.workspace_url and self.connection_id:
445            return f"{self.workspace_url}/connections/{self.connection_id}"
446
447        return None
448
449    @property
450    def job_history_url(self) -> str | None:
451        """The URL to the job history where the error occurred."""
452        if self.connection_url:
453            return f"{self.connection_url}/job-history"
454
455        return None
456
457    @property
458    def job_url(self) -> str | None:
459        """The URL to the job where the error occurred."""
460        if self.job_history_url and self.job_id:
461            return f"{self.job_history_url}#{self.job_id}::0"
462
463        return None

An connection error occurred while communicating with the hosted Airbyte instance.

AirbyteConnectionError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None, workspace: airbyte.cloud.CloudWorkspace | None = None, connection_id: str | None = None, job_id: str | None = None, job_status: str | None = None)
connection_id: str | None = None

The connection ID where the error occurred.

job_id: str | None = None

The job ID where the error occurred (if applicable).

job_status: str | None = None

The latest status of the job where the error occurred (if applicable).

connection_url: str | None
441    @property
442    def connection_url(self) -> str | None:
443        """The URL to the connection where the error occurred."""
444        if self.workspace_url and self.connection_id:
445            return f"{self.workspace_url}/connections/{self.connection_id}"
446
447        return None

The URL to the connection where the error occurred.

job_history_url: str | None
449    @property
450    def job_history_url(self) -> str | None:
451        """The URL to the job history where the error occurred."""
452        if self.connection_url:
453            return f"{self.connection_url}/job-history"
454
455        return None

The URL to the job history where the error occurred.

job_url: str | None
457    @property
458    def job_url(self) -> str | None:
459        """The URL to the job where the error occurred."""
460        if self.job_history_url and self.job_id:
461            return f"{self.job_history_url}#{self.job_id}::0"
462
463        return None

The URL to the job where the error occurred.

@dataclass
class AirbyteConnectionSyncError(AirbyteConnectionError):
466@dataclass
467class AirbyteConnectionSyncError(AirbyteConnectionError):
468    """An error occurred while executing the remote Airbyte job."""

An error occurred while executing the remote Airbyte job.

AirbyteConnectionSyncError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None, workspace: airbyte.cloud.CloudWorkspace | None = None, connection_id: str | None = None, job_id: str | None = None, job_status: str | None = None)
@dataclass
class AirbyteConnectionSyncTimeoutError(AirbyteConnectionSyncError):
471@dataclass
472class AirbyteConnectionSyncTimeoutError(AirbyteConnectionSyncError):
473    """An timeout occurred while waiting for the remote Airbyte job to complete."""
474
475    timeout: int | None = None
476    """The timeout in seconds that was reached."""

An timeout occurred while waiting for the remote Airbyte job to complete.

AirbyteConnectionSyncTimeoutError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None, workspace: airbyte.cloud.CloudWorkspace | None = None, connection_id: str | None = None, job_id: str | None = None, job_status: str | None = None, timeout: int | None = None)
timeout: int | None = None

The timeout in seconds that was reached.

@dataclass
class AirbyteMissingResourceError(AirbyteError):
482@dataclass
483class AirbyteMissingResourceError(AirbyteError):
484    """Remote Airbyte resources does not exist."""
485
486    resource_type: str | None = None
487    resource_name_or_id: str | None = None

Remote Airbyte resources does not exist.

AirbyteMissingResourceError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None, workspace: airbyte.cloud.CloudWorkspace | None = None, resource_type: str | None = None, resource_name_or_id: str | None = None)
resource_type: str | None = None
resource_name_or_id: str | None = None
@dataclass
class AirbyteMultipleResourcesError(AirbyteError):
490@dataclass
491class AirbyteMultipleResourcesError(AirbyteError):
492    """Could not locate the resource because multiple matching resources were found."""
493
494    resource_type: str | None = None
495    resource_name_or_id: str | None = None

Could not locate the resource because multiple matching resources were found.

AirbyteMultipleResourcesError( guidance: str | None = None, help_url: str | None = None, log_text: str | list[str] | None = None, log_file: pathlib.Path | None = None, context: dict[str, typing.Any] | None = None, message: str | None = None, original_exception: Exception | None = None, response: airbyte._util.api_duck_types.AirbyteApiResponseDuckType | None = None, workspace: airbyte.cloud.CloudWorkspace | None = None, resource_type: str | None = None, resource_name_or_id: str | None = None)
resource_type: str | None = None
resource_name_or_id: str | None = None
class AirbyteExperimentalFeatureWarning(builtins.FutureWarning):
501class AirbyteExperimentalFeatureWarning(FutureWarning):
502    """Warning whenever using experimental features in PyAirbyte."""

Warning whenever using experimental features in PyAirbyte.

Inherited Members
builtins.FutureWarning
FutureWarning
builtins.BaseException
with_traceback
args
class PyAirbyteWarning(builtins.Warning):
508class PyAirbyteWarning(Warning):
509    """General warnings from PyAirbyte."""

General warnings from PyAirbyte.

Inherited Members
builtins.Warning
Warning
builtins.BaseException
with_traceback
args
class PyAirbyteDataLossWarning(PyAirbyteWarning):
512class PyAirbyteDataLossWarning(PyAirbyteWarning):
513    """Warning for potential data loss.
514
515    Users can ignore this warning by running:
516    > warnings.filterwarnings("ignore", category="airbyte.exceptions.PyAirbyteDataLossWarning")
517    """

Warning for potential data loss.

Users can ignore this warning by running:

warnings.filterwarnings("ignore", category="airbyte.exceptions.PyAirbyteDataLossWarning")

Inherited Members
builtins.Warning
Warning
builtins.BaseException
with_traceback
args