fix/duckdb/catalog-error
DuckDB error

Catalog Error

Updated Aug 27, 20266-min read
TL;DR

DuckDB could not find the table, view, column, function, schema, or sequence you named. The catalog is DuckDB's index of every named object it knows about, and this error means the name in your query is not in it.

  • ·The name is misspelled (DuckDB often prints a Did you mean suggestion right in the error)
  • ·The object lives in a different database or schema and needs a qualified name like catalog.schema.table
  • ·You are in an in-memory session and the CREATE ran on a different connection, so this connection sees an empty catalog
  • ·The identifier was double-quoted at CREATE time and is case-sensitive, but you are referencing it unquoted
  • ·The function belongs to an extension that has not been loaded (read_excel, ST_*, read_json_auto, etc.)
CHECK FIRSTRun SHOW TABLES and SHOW DATABASES. If the object is not there, you are either on the wrong connection or the wrong database. The name in the error is what DuckDB actually looked up.

What you're seeing

The wording varies by which kind of catalog entry is missing, but every variant starts with Catalog Error and names the specific object type. DuckDB usually appends a fuzzy-match suggestion.

text
Catalog Error: Table with name orders does not exist!
Did you mean "main.order"?

Catalog Error: Table "customers" does not have a column named "emial"
Did you mean "email"?

Catalog Error: Scalar Function with name read_excel does not exist!
Did you mean "read_text"?

Catalog Error: Schema with name analytics does not exist!

# Python client variant:
duckdb.CatalogException: Catalog Error: Table with name orders does not exist!
Also seen as: duckdb catalog error, duckdb catalog exception, CatalogException, Table with name does not exist, Schema with name does not exist, Function with name does not exist

What's causing this

Ranked most-likely first.

  1. 1

    The name is misspelled or the wrong casing was quoted at creation

    Simplest and most common. DuckDB folds unquoted identifiers to lowercase but preserves case for double-quoted ones. If a table was created as CREATE TABLE "MyTable", then SELECT * FROM MyTable looks up mytable and misses. The Did you mean suggestion in the error usually points straight at the real name.

  2. 2

    The object lives in a different database or schema

    DuckDB supports multiple attached databases and multiple schemas per database. An unqualified name resolves against the current catalog and search_path only. A table in the analytics database or the raw schema needs analytics.main.orders or raw.orders, unless you first USE it.

  3. 3

    You are on a different connection than the one that ran CREATE

    In-memory databases are private to the connection unless opened as a shared in-memory instance. If one script creates a table on con1 and another script queries on con2, con2 sees an empty catalog. Same pattern with Jupyter notebooks when the kernel restarts between cells.

  4. 4

    The database file was never attached or the ATTACH failed silently

    Opening DuckDB with no file gives you an empty in-memory catalog. If you meant to open orders.duckdb, you need duckdb.connect('orders.duckdb') or an ATTACH statement. A wrong path opens a fresh empty database rather than erroring.

  5. 5

    The function lives in an extension that is not loaded

    read_excel, ST_Point, read_json_auto with certain modes, iceberg_scan, and other functions ship in optional extensions. Until you INSTALL and LOAD the extension, DuckDB reports the function as a missing catalog entry with a Did you mean suggestion pointing at a similar built-in name.

  6. 6

    The object was dropped, renamed, or replaced

    A CREATE OR REPLACE with a typo, an ALTER TABLE ... RENAME TO, or a stale migration will leave the old name gone. If the missing name looks like an older version of an object, check the migration history.

  7. 7

    A Python DataFrame or Arrow table was not registered

    DuckDB's Python client can query pandas or polars DataFrames by variable name, but only inside con.execute or con.sql on the same connection that has the variable in scope. Passing the query string across connections, threads, or subprocesses drops the reference and the catalog lookup fails.

How to fix it

Step 1: list what the catalog actually contains

Confirm the object is really missing before assuming a bug. These queries show you every table, schema, and attached database DuckDB currently knows about.

sql
SHOW DATABASES;
SHOW SCHEMAS;
SHOW TABLES;

-- Or query information_schema for a specific name:
SELECT table_catalog, table_schema, table_name
FROM information_schema.tables
WHERE table_name ILIKE '%order%';

-- For a missing function:
SELECT function_name, function_type, database_name
FROM duckdb_functions()
WHERE function_name ILIKE '%read_excel%';

Step 2: use the fully qualified name if the object is in another database or schema

If SHOW DATABASES lists more than one entry, unqualified names only resolve against the current one. Fully qualify with catalog.schema.object, or switch context with USE.

sql
-- Fully qualified:
SELECT * FROM analytics.main.orders;

-- Or switch context for the session:
USE analytics;
SELECT * FROM orders;

-- If the database is not attached yet:
ATTACH 'analytics.duckdb' AS analytics;

Step 3: check identifier casing

DuckDB is case-insensitive for unquoted identifiers, but it preserves case for quoted ones. If a name was created with double quotes and mixed case, every reference has to use the same quoted form.

sql
-- These all resolve to the same table (unquoted, lowercased):
SELECT * FROM Orders;
SELECT * FROM ORDERS;
SELECT * FROM orders;

-- But this created a distinct, case-sensitive name:
CREATE TABLE "MyTable" (id INT);

-- So this fails:
SELECT * FROM MyTable;   -- looks up "mytable"

-- Match the original quoting:
SELECT * FROM "MyTable";

Step 4: install and load the extension if the function is missing

If the missing entry is a function like read_excel, ST_Point, or iceberg_scan, the fix is to install the extension that provides it. INSTALL downloads it once, LOAD activates it for the current session.

sql
-- Excel reader:
INSTALL excel;
LOAD excel;

-- Spatial functions:
INSTALL spatial;
LOAD spatial;

-- List everything currently loaded:
SELECT extension_name, loaded, installed
FROM duckdb_extensions()
WHERE loaded OR installed;

Step 5: open the right database file, not a fresh in-memory one

If SHOW TABLES is empty and you expected data, you probably opened a new in-memory instance instead of your file. Pass the path to connect() or ATTACH the file explicitly.

python
import duckdb

# Wrong: brand new empty in-memory database
con = duckdb.connect()

# Right: open the persistent file
con = duckdb.connect('warehouse.duckdb')

# Or from an in-memory session, attach it:
con = duckdb.connect()
con.execute("ATTACH 'warehouse.duckdb' AS warehouse")
con.execute("USE warehouse")

Step 6: register Python DataFrames on the connection you are querying

When querying a pandas or polars DataFrame from Python, either query it on the connection that has it in scope, or register it explicitly so it lives in the catalog by a stable name.

python
import duckdb
import pandas as pd

df = pd.read_csv('orders.csv')
con = duckdb.connect()

# Register the DataFrame as a named view:
con.register('orders', df)
con.execute("SELECT COUNT(*) FROM orders").fetchall()

# Or query directly on the module (works only in the caller's scope):
duckdb.sql("SELECT COUNT(*) FROM df").fetchall()

Step 7: recreate the object if it was dropped or renamed

If a migration or a stray DROP removed the object, the fix is to recreate it. Guard future runs with IF NOT EXISTS or CREATE OR REPLACE so a repeat run stops erroring.

sql
CREATE TABLE IF NOT EXISTS orders (
  id BIGINT PRIMARY KEY,
  customer_id BIGINT,
  total DECIMAL(10, 2),
  created_at TIMESTAMP
);

-- Or replace on every run for a reproducible setup:
CREATE OR REPLACE VIEW recent_orders AS
SELECT * FROM orders WHERE created_at > now() - INTERVAL 30 DAY;

Prevention

Prefer unquoted identifiers when creating tables, columns, and functions. DuckDB folds them to lowercase and lookups become case-insensitive, which removes an entire class of catalog errors without any effort at query time.

For persistent workloads, always open DuckDB with a real file path and log which catalog you attached at startup. A misconfigured connection string opening a fresh in-memory database is one of the most common ways this error surfaces in production.

In Python and notebooks, keep one long-lived connection per process instead of reconnecting for each query. It preserves the catalog, avoids extension reloads, and keeps registered DataFrames and views visible to every subsequent query.

Debug DuckDB faster

1bench is a native GUI for DuckDB. Inspect queries, connections, and settings without leaving the app. See what's happening before you have to Google it.

Open DuckDB in 1bench