DuckDB parsed your query fine but the binder, the phase that resolves identifiers against the catalog, could not match a column, table, function, or type to anything it knows about. Almost always a typo, a missing FROM, an ambiguous column across joined tables, or a function call whose argument types no longer match the signature (a common DuckDB 0.10 upgrade break).
The query fails at plan time, before any rows are read. The message always starts with 'Binder Error:' and names the identifier that could not be resolved. DuckDB usually also prints a 'Candidate' list of near-matches from the catalog.
Error: Binder Error: Referenced column "user_id" not found in FROM clause!
Candidate bindings: "users.id", "users.user_uuid"
LINE 1: SELECT user_id FROM users;
^
Error: Binder Error: Referenced table "foobar" not found!
Candidate tables: "foo_bar"
Error: Binder Error: Ambiguous reference to column name "id" (use: "users.id" or "orders.id")
Error: Binder Error: No function matches the given name and argument types 'strptime(BIGINT, STRING_LITERAL)'. You might need to add explicit type casts.
Candidate functions:
strptime(VARCHAR, VARCHAR) -> TIMESTAMP
strptime(VARCHAR, VARCHAR[]) -> TIMESTAMPduckdb binder error, BinderException, duckdb.BinderException, Referenced column not found in FROM clause, Referenced table not found, Ambiguous reference to column name, No function matches the given name and argument typesRanked most-likely first.
The binder resolves column names against the exact identifiers in the catalog. 'user_id' does not match 'userId', 'UserID', or 'users.id'. If the column came from a Parquet or CSV, run DESCRIBE on the file to see what DuckDB actually parsed the column names as.
DuckDB reports this as 'Referenced column X not found in FROM clause!' rather than 'no FROM clause'. If you copy-pasted a projection without its FROM, or your CTE forgot to reference the base table, the message reads as a column problem but the real issue is that nothing is in scope.
When two tables in a JOIN share a column name and the SELECT list or WHERE clause references it unqualified, the binder cannot pick one and errors with 'Ambiguous reference to column name X (use: table1.X or table2.X)'. Very common after adding a second table to an existing query.
DuckDB 0.10 removed most implicit casts to VARCHAR during function binding, so calls that used to work like strptime(some_bigint, '%Y%m%d') now error. Same for lists, structs, and enums where the exact type has to line up. The message lists 'Candidate functions' with the signatures that do exist.
The table was never created, was dropped, lives in a different schema, or lives in an attached database whose alias you omitted. Correlated subqueries and CTEs can also produce misleading 'Referenced table' errors when the real issue is a missing column on a table that does exist.
Accessing a struct field with dot syntax (row.field) or bracket notation errors at bind time if the field is not in the struct's declared schema. JSON path lookups behave differently and return NULL rather than a Binder Error, but STRUCT and MAP types are strict.
The error names exactly what could not be bound, in double quotes. Run DESCRIBE on the source table (or SELECT * LIMIT 0 on a file) and compare character for character. Casing counts, and underscores versus camelCase counts.
DESCRIBE users;
-- Or for a file source:
SELECT * FROM 'events.parquet' LIMIT 0;
-- To list every column across every table in the current schema:
SELECT table_name, column_name FROM information_schema.columns
WHERE table_schema = 'main';DuckDB prints near-matches under 'Candidate bindings' or 'Candidate tables'. That list is generated from the identifiers currently in scope, so it is authoritative for what the binder can see. If your identifier is not in it, the object is either misnamed or not in scope.
Binder Error: Referenced column "user_id" not found in FROM clause!
Candidate bindings: "users.id", "users.user_uuid"
-- The catalog has users.id and users.user_uuid.
-- If you wanted the primary key, use users.id.For 'Ambiguous reference to column name', prefix every reference with the table name or alias. Do this for every occurrence, not just the one the error names, or the next binder pass will trip on the next one.
-- Instead of:
SELECT id, name FROM users JOIN orders ON users.id = orders.user_id;
-- Qualify:
SELECT users.id, users.name FROM users
JOIN orders ON users.id = orders.user_id;
-- Or alias the tables:
SELECT u.id, u.name FROM users u
JOIN orders o ON u.id = o.user_id;The Candidate functions list in the error shows the signatures DuckDB has. Cast your arguments to match one of them. Very common after upgrading to DuckDB 0.10 or later, where implicit VARCHAR casts were removed.
-- Fails on DuckDB 0.10+:
SELECT strptime(date_of_birth, '%Y%m%d') FROM people;
-- Error: strptime(BIGINT, STRING_LITERAL) has no match
-- Fix with an explicit cast to VARCHAR:
SELECT strptime(CAST(date_of_birth AS VARCHAR), '%Y%m%d') FROM people;
-- Or:
SELECT strptime(date_of_birth::VARCHAR, '%Y%m%d') FROM people;If the error says 'Referenced column X not found in FROM clause!' and you cannot see what is wrong, check that the query has a FROM at all. This trips up copy-paste of an inner subquery, or a CTE whose SELECT references a column it forgot to pull from anywhere.
-- Fails: no FROM, so no column is in scope:
SELECT user_id, COUNT(*);
-- Fix: add the source:
SELECT user_id, COUNT(*) FROM events GROUP BY user_id;'Referenced table X not found!' can mean the table lives in a schema you did not qualify, or in an attached database whose alias you dropped. Run SHOW ALL TABLES to see what the binder can actually resolve, and SHOW DATABASES to see which attachments are live.
SHOW ALL TABLES;
SHOW DATABASES;
-- Qualify with schema or database if needed:
SELECT * FROM analytics.events;
SELECT * FROM warehouse.public.orders;
-- Or set the default search path so unqualified names resolve:
SET search_path = 'analytics';STRUCT types are strict about field names at bind time. DESCRIBE the column, or use struct_extract with the literal field name to see the schema DuckDB has stored. Field names inside structs are also case-sensitive.
-- See the struct's field layout:
SELECT typeof(payload) FROM events LIMIT 1;
-- If the struct has {user_id INTEGER, ts TIMESTAMP}, this errors:
SELECT payload.userId FROM events;
-- Binder Error: Struct does not have field "userId"
-- Use the actual field name:
SELECT payload.user_id FROM events;Alias your tables in every JOIN, even when it feels verbose, and qualify every column reference. It costs nothing to write and removes an entire class of ambiguity errors before they happen.
When you upgrade DuckDB across a minor version, run your query suite in CI against the new version before promoting it. The 0.10 release quietly broke a lot of queries that relied on implicit VARCHAR casts, and other minor versions have tightened function binding in similar ways.
For code that queries user-supplied identifiers (dashboards, notebooks), catch BinderException in the client and surface DuckDB's Candidate list to the user. That message is the fastest hint about what the right identifier is, and hiding it behind a generic 'query failed' banner wastes it.
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