Skip to content

Improve NotFoundError message propagation for DuckDB catalog errors #294

@cofin

Description

@cofin

Description

When a DuckDB catalog error occurs (e.g., referencing a table or CTE that doesn't exist), the NotFoundError exception is raised but the original error message is not easily accessible when logging or displaying the error.

Current Behavior

The _raise_not_found_error method in sqlspec/adapters/duckdb/driver.py creates a descriptive message:

def _raise_not_found_error(self, e: Any) -> None:
    msg = f"DuckDB catalog error: {e}"
    raise NotFoundError(msg) from e

However, when catching and logging this exception, the message is stored in the .detail attribute (inherited from SQLSpecError), not in .args. This means common logging patterns like:

except Exception as e:
    logger.error(f"Failed: {type(e).__name__}{e.args}")  # Shows: NotFoundError()

...produce empty output instead of the useful error message.

Expected Behavior

The error message should be easily accessible via standard exception patterns:

  1. str(e) should return the full message (this works via __str__)
  2. e.args should contain the message for compatibility with standard exception handling
  3. repr(e) should show the detail for debugging

Suggested Improvements

Option 1: Populate .args in SQLSpecError.__init__

def __init__(self, *args: Any, detail: str = "") -> None:
    str_args = [str(arg) for arg in args if arg]
    if not detail:
        if str_args:
            detail, *str_args = str_args
        elif hasattr(self, "detail"):
            detail = self.detail
    self.detail = detail
    # Also store in args for standard exception compatibility
    super().__init__(detail, *str_args)  # <-- Include detail in args

Option 2: Include query context in errors

When executing named queries via SQLSpec, include the query name in error messages:

def execute(self, query_name: str, ...):
    try:
        return self._driver.execute(self._db_manager.get_sql(query_name), ...)
    except NotFoundError as e:
        raise NotFoundError(f"Query '{query_name}' failed: {e.detail}") from e

This would produce errors like:

NotFoundError: Query 'transform_05_00_db_summary' failed: DuckDB catalog error: Table 'current_features' does not exist

Environment

  • sqlspec version: (latest)
  • Python: 3.12
  • Discovered while debugging DMA (Database Migration Assistant) assessment failures

Workaround

Currently using str(e) instead of e.args for logging:

except Exception as e:
    logger.error(f"Failed: {type(e).__name__}: {e}")  # Works correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions