cube-js/cube · error
Unable to describe table
Error message
Unable to describe table
What it means
queryColumnTypes() runs `DESCRIBE (<sql>)` against ClickHouse to infer column names/types, and throws when the query returns no columns (falsy result). It is called by the types()/downloadQueryResults metadata path, so a table-less or non-selectable query breaks type inference.
Source
Thrown at packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts:579
public async isUnloadSupported() {
return !!this.config.exportBucket;
}
/**
* Returns an array of queried fields meta info.
*/
public async queryColumnTypes(sql: string, params: unknown[]): Promise<TableStructure> {
// For DESCRIBE we expect that each row would have special structure
// See https://clickhouse.com/docs/en/sql-reference/statements/describe-table
// TODO complete this type
type DescribeRow = {
name: string,
type: string
};
const columns = await this.query<DescribeRow>(`DESCRIBE ${sql}`, params);
if (!columns) {
throw new Error('Unable to describe table');
}
return columns.map((column) => ({
name: column.name,
type: this.toGenericType(column.type),
}));
}
// This is only for use in tests
public override async createTableRaw(query: string): Promise<void> {
await this.command(query);
}
public override async createTable(quotedTableName: string, columns: TableColumn[]) {
const createTableSql = this.createTableSql(quotedTableName, columns);
try {
await this.command(createTableSql);
} catch (e) {View on GitHub (pinned to 7d981676b3)
Solutions
- Grant the ClickHouse user DESCRIBE/metadata privileges on the underlying tables and database
- Run `DESCRIBE (<sql>)` manually in clickhouse-client to see why it returns nothing
- Verify the sql/params passed to types() reference existing tables/views
- Upgrade driver/ClickHouse — older versions could return empty metadata for certain engines
- If using a custom/mock driver implementation, ensure query() resolves with the rows array rather than undefined
Example fix
// before (test mock)
query: async () => undefined
// after
query: async () => [{ name: 'id', type: 'UInt64' }] Defensive patterns
Strategy: validation
Validate before calling
// Ensure the user can describe the target table before calling types()
await clickhouseClient.exec({ query: `DESCRIBE TABLE my_db.my_table` }); Type guard
const isDescribable = (cols: unknown): cols is Array<{ name: string; type: string }> =>
Array.isArray(cols) && cols.length > 0 && cols.every(c => typeof c?.name === 'string' && typeof c?.type === 'string'); Try / catch
try { return await driver.downloadQueryResults(q, v); }
catch (e) {
if (String(e.message) === 'Unable to describe table') throw new Error('Check DESCRIBE privileges and that the query targets existing tables', { cause: e });
throw e;
} Prevention
- GRANT DESCRIBE/metadata privileges to the Cube ClickHouse user
- Verify referenced tables/views exist in the target database
- Run the DESCRIBE wrapper query manually when debugging
When it happens
Trigger: Calling types() (e.g. during pre-aggregation load checks) with a query whose DESCRIBE yields no rows/columns — e.g. an empty result set from DESCRIBE, permission-restricted metadata, or a subquery ClickHouse cannot describe.
Common situations: Querying a view or table the ClickHouse user lacks DESCRIBE privileges on; queries against empty/temporary tables in some ClickHouse versions returning no metadata; malformed sql wrapped by the caller; mocked drivers in tests returning undefined from query().
Related errors
- Create table failed: ${e}
- options.meta must be a function
- Unable to retrieve list of files from S3 storage after unloa
- No CSV files were obtained from the bucket
- No CSV files were obtained from the bucket
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/45f6cd2374aed3db.
Report an issue: GitHub.