cube-js/cube · error

Query failed: ${e}; query id: ${queryId}

Error message

Query failed: ${e}; query id: ${queryId}

What it means

queryResponse wraps the entire execute/json parsing of a ClickHouse query in try/catch and rethrows as `Query failed: <original error>; query id: <queryId>`. This normalizes all client errors (network, HTTP status, parsing, ClickHouse SQL errors) into one message while preserving the query id so the failing query can be found in ClickHouse's query_log.

Source

Thrown at packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts:302

          query: formattedQuery,
          query_id: queryId,
          format,
          clickhouse_settings: this.config.clickhouseSettings,
          abort_signal: signal,
        });

        // response_headers['x-clickhouse-format'] is optional, but if it exists,
        // it should match the requested format.
        if (resultSet.response_headers['x-clickhouse-format'] && resultSet.response_headers['x-clickhouse-format'] !== format) {
          throw new Error(`Unexpected x-clickhouse-format in response: expected ${format}, received ${resultSet.response_headers['x-clickhouse-format']}`);
        }

        // We used format JSON, so we expect each row to be Record with column names as keys
        const results = await resultSet.json<Record<string, unknown>>();
        return results;
      } catch (e) {
        // TODO replace string formatting with proper cause
        throw new Error(`Query failed: ${e}; query id: ${queryId}`);
      }
    });
  }

  protected normaliseResponse<R = unknown>(res: ResponseJSON<Record<string, unknown>>): Array<R> {
    if (res.data) {
      const meta = (res.meta ?? []).reduce<Record<string, { name: string; type: string; }>>(
        (state, element) => ({ [element.name]: element, ...state }),
        {}
      );

      // TODO maybe use row-based format here as well?
      res.data.forEach((row) => {
        transformRow(row, meta);
      });
    }
    return res.data as Array<R>;
  }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Copy the query id from the message and run `SELECT * FROM system.query_log WHERE query_id = '<id>'` (or check the server log) for the real ClickHouse error
  2. Fix the underlying SQL/model issue indicated by the nested error text after 'Query failed:'
  3. Verify ClickHouse user permissions and database/table existence
  4. Check clickhouse server logs at the timestamp for full stack/exception text

Example fix

// before: measure references missing column
-- Code: 47 UNKNOWN_IDENTIFIER: amount_typo
// after: fix the sql in the cube schema
measure: { sql: `amount`, type: `sum` }
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const rows = await cube.query(query);
} catch (e) {
  const m = e.message.match(/^Query failed: (.*); query id: ([\w-]+)/s);
  if (m) {
    const [, cause, queryId] = m;
    logger.error({ cause, queryId }, 'ClickHouse query failed'); // look up queryId in system.query_log
  }
  throw e;
}

Prevention

When it happens

Trigger: Any failure during query() execution in queryResponse: ClickHouse SQL error (syntax, unknown identifier), HTTP 4xx/5xx from the server, aborted request, or resultSet.json() parse failure.

Common situations: Typos in generated SQL from a bad data model; ClickHouse throwing UNKNOWN_IDENTIFIER for a missing column; auth failures (403 from ClickHouse user); queries killed by user-level timeout; schema drift after table changes.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/3d99438c78aaf5f5. Report an issue: GitHub.