cube-js/cube · error
${response.status === 401 ? 'Unauthorized request' : 'Unexpe
Error message
${response.status === 401 ? 'Unauthorized request' : 'Unexpected error'} What it means
The Pinot driver's `request()` performs a POST of the SQL query to the Pinot broker/controller. If the HTTP response is not ok, the driver throws a generic Error — 'Unauthorized request' for HTTP 401, or the opaque 'Unexpected error' for every other non-2xx status (403, 404, 500, 503, etc.). The thrown message discards the real status code and response body, so non-401 failures are hard to diagnose.
Source
Thrown at packages/cubejs-pinot-driver/src/PinotDriver.ts:196
'Content-Type': 'application/json',
...this.authorizationHeaders()
}),
body: JSON.stringify({
sql: query,
queryOptions: `useMultistageEngine=true;enableNullHandling=${this.config.nullHandling};timeoutMs=${this.config.queryTimeout * 1000}`
})
});
let response: Response;
try {
response = await fetch(request);
} catch (error: any) {
throw toError(error);
}
if (!response.ok) {
throw toError({ message: response.status === 401 ? 'Unauthorized request' : 'Unexpected error' });
}
const result: PinotResponse = await response.json();
if (result?.exceptions?.length) {
throw toError(result.exceptions[0]);
}
return result;
}
public async queryPromised(query: string): Promise<any[] | StreamTableData> {
const { resultTable } = await this.request(query);
return this.normalizeResultOverColumns(resultTable.rows, resultTable.dataSchema.columnNames);
}
public async downloadQueryResults(
query: string,View on GitHub (pinned to 7d981676b3)
Solutions
- If the message is 'Unauthorized request', verify the authToken (Bearer) or basicAuth user/password in the driver config and regenerate the token if expired.
- Log `response.status` and the response body around the call (or curl the broker endpoint with the same headers/body) to see the real error for non-401 statuses.
- Verify this.url points to the Pinot BROKER query endpoint (http://<broker>:8099/query/sql style) and is reachable from the Cube process.
- Check Pinot broker health/logs for 5xx causes (broker down, table missing, query timeout) and retry once the cluster is healthy.
- Patch/upgrade the driver to include response.status and body text in the thrown error for easier debugging.
Example fix
// before
if (!response.ok) {
throw toError({ message: response.status === 401 ? 'Unauthorized request' : 'Unexpected error' });
}
// after
if (!response.ok) {
const body = await response.text().catch(() => '');
throw toError({ message: `Pinot request failed (${response.status}): ${body || response.statusText}` });
} Defensive patterns
Strategy: try-catch
Validate before calling
function validatePinotConfig(config: { authToken?: string; basicAuth?: { user: string; password: string }; url: string }) {
if (!config.url || !/^https?:\/\//.test(config.url)) {
throw new Error('Pinot broker URL must be an absolute http(s) URL');
}
if (!config.authToken && !config.basicAuth) {
console.warn('No Pinot credentials configured; requests may return 401 Unauthorized');
}
} Type guard
function isUnauthorizedError(err: unknown): err is Error {
return err instanceof Error && err.message === 'Unauthorized request';
} Try / catch
try {
const rows = await driver.queryPromised(sql);
} catch (err) {
if (err instanceof Error && err.message === 'Unauthorized request') {
// refresh/rotate the Pinot authToken or basicAuth credentials, then retry once
await refreshCredentials();
return driver.queryPromised(sql);
}
if (err instanceof Error && err.message === 'Unexpected error') {
// inspect broker health/logs; opaque 4xx/5xx — log context and retry with backoff
await retryWithBackoff(() => driver.queryPromised(sql));
return;
}
throw err;
} Prevention
- Configure a valid, unexpired authToken (Bearer) or basicAuth credentials for the Pinot cluster.
- Point the driver URL at the Pinot broker query endpoint, not the controller, and confirm the port is reachable.
- Pre-flight check the endpoint with curl using the same Authorization headers before deploying.
- Handle token rotation: re-create or reconfigure the driver when credentials are refreshed.
- Check Pinot broker health and logs when you see 'Unexpected error', since the driver hides the real status/body.
When it happens
Trigger: Any Pinot SQL request (`queryPromised` / `downloadQueryResults`, reached via resultTable destructure) where `fetch` returns a non-ok status: 401 with a wrong/expired/missing authToken or basicAuth credentials, 403 from broker ACLs, 404 from a wrong broker URL/port, or 5xx when brokers are down or the query crashes the server.
Common situations: Misconfigured or expired Pinot auth token in cube.js config; wrong `basicAuth` user/password; broker URL pointing at controller instead of broker (or wrong port); Pinot cluster restarted/upgraded returning 503; TLS/proxy issues turning a healthy cluster into an erroring endpoint.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to get access token: ${res.statusText}
- Databricks API error: ${res.statusText}
- Can't fetch metrics from Dbt Cloud: ${res.errors[0].message}
- HTTP error! status: ${response.status}
- unexpected response ${response.statusText}
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/0603828a79e3ac38.
Report an issue: GitHub.