{"record":{"id":"2d4ecc8c0eeba899","repo":"cube-js/cube","slug":"query-must-be-defined-in-options","errorCode":null,"errorMessage":"Query must be defined in options","messagePattern":"Query must be defined in options","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts","lineNumber":608,"sourceCode":"    await this.command(query);\n  }\n\n  public override async createTable(quotedTableName: string, columns: TableColumn[]) {\n    const createTableSql = this.createTableSql(quotedTableName, columns);\n    try {\n      await this.command(createTableSql);\n    } catch (e) {\n      // TODO replace string formatting with proper cause\n      throw new Error(`Create table failed: ${e}`);\n    }\n  }\n\n  /**\n   * We use unloadWithoutTempTable strategy\n   */\n  public async unload(_tableName: string, options: UnloadOptions): Promise<DownloadTableCSVData> {\n    if (!options.query?.sql) {\n      throw new Error('Query must be defined in options');\n    }\n\n    return this.unloadFromQuery(\n      options.query?.sql,\n      options.query?.params,\n      options\n    );\n  }\n\n  public async unloadFromQuery(sql: string, params: unknown[], _options: UnloadOptions): Promise<DownloadTableCSVData> {\n    if (!this.config.exportBucket) {\n      throw new Error('Unload is not configured');\n    }\n\n    const types = await this.queryColumnTypes(`(${sql})`, params);\n    const { bucketName, path } = this.parseBucketUrl(this.config.exportBucket.bucketName);\n    const exportPrefix = path ? `${path}/${uuidv4()}` : uuidv4();\n","sourceCodeStart":590,"sourceCodeEnd":626,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-clickhouse-driver/src/ClickHouseDriver.ts#L590-L626","documentation":"A validation guard in ClickHouseDriver.unload: unloading a table in the ClickHouse driver is implemented by running a caller-supplied SELECT (`options.query.sql`) and inserting its results, since ClickHouse has no native server-side unload API. Throwing when options.query is missing means unloadWithoutTempTable strategy was requested without defining the source query; callers must pass a query in UnloadOptions.","triggerScenarios":"Calling driver.unload(tableName, options) with options lacking a query object, or with query defined but sql undefined/empty — typically from an orchestrator/pre-aggregation path that did not populate UnloadOptions.query.","commonSituations":"Custom code calling unload() directly with only a table name; drivers/configurations where the unload strategy (unloadWithoutTempTable) is set but the caller builds UnloadOptions without query; null propagation from upstream query builders.","solutions":["Ensure the caller passes options.query = { sql, params } when invoking unload()","Verify the pre-aggregation unload strategy configuration so Cube's orchestrator populates UnloadOptions.query","If calling manually, use unloadFromQuery(sql, params, options) instead when you have raw SQL","Add a guard in calling code to fail fast with a clear message before invoking unload()"],"exampleFix":"// before\nawait driver.unload('my_preagg', {} as UnloadOptions);\n// after\nawait driver.unload('my_preagg', { query: { sql: 'SELECT ...', params: [] } } as UnloadOptions);","handlingStrategy":"validation","validationCode":"const canUnload = (options?: UnloadOptions): options is UnloadOptions & { query: { sql: string; params: unknown[] } } =>\n  Boolean(options?.query?.sql);","typeGuard":"const hasUnloadQuery = (o: UnloadOptions): o is UnloadOptions & { query: { sql: string; params: unknown[] } } =>\n  typeof o?.query?.sql === 'string' && o.query.sql.length > 0;","tryCatchPattern":"try { return await driver.unload(table, options); }\ncatch (e) {\n  if (String(e.message) === 'Query must be defined in options') throw new Error('UnloadOptions.query.sql is required for unload', { cause: e });\n  throw e;\n}","preventionTips":["Always populate UnloadOptions.query with { sql, params }","Prefer unloadFromQuery() when calling manually with raw SQL","Fail fast in calling code before invoking unload()"],"tags":["configuration","api-misuse","clickhouse","unload"],"backgroundTag":"missing-required-option","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}