cube-js/cube · error · UserError
Can't fetch metrics from Dbt Cloud: ${res.errors[0].message}
Error message
Can't fetch metrics from Dbt Cloud: ${res.errors[0].message} What it means
loadMetricCubesFromDbtCloud executes a GraphQL query against the Dbt Cloud Discovery API (with a bearer token and jobId). If the response body contains a non-empty errors array, the first error message from the API is surfaced wrapped in this UserError.
Source
Thrown at packages/cubejs-dbt-schema-extension/src/Dbt.ts:173
const modelName = match[1];
metricDef.model = modelName.indexOf('.') !== -1 ? modelName : `model.${metricDef.package_name}.${modelName}`;
});
return this.loadMetricCubesFromNormalizedManifest(manifest, manifestPath, options);
}
public async loadMetricCubesFromDbtCloud(jobId: string | number, authToken: string, options: DbtLoadOptions): Promise<{ [cubeName: string]: any }> {
const response = await fetch('https://metadata.cloud.getdbt.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${authToken}`
},
body: JSON.stringify({ query: loadModelsQuery, variables: { jobId } })
});
const res = <GraphqlResponse>(await response.json());
if (res.errors && res.errors.length > 0) {
throw new UserError(`Can't fetch metrics from Dbt Cloud: ${res.errors[0].message}`);
}
const manifest: DbtManifest = {
metrics: res.data.metrics.map(metricDef => ({
[metricDef.uniqueId]: {
unique_id: metricDef.uniqueId,
name: metricDef.name,
model: metricDef.model.uniqueId,
// eslint-disable-next-line camelcase
package_name: metricDef.packageName,
type: metricDef.type,
sql: metricDef.sql,
dimensions: metricDef.dimensions,
timestamp: metricDef.timestamp,
}
})).reduce((a, b) => ({ ...a, ...b }), {}),
nodes: res.data.models.map(modelDef => ({
[modelDef.uniqueId]: {
database: modelDef.database,View on GitHub (pinned to 7d981676b3)
Solutions
- Verify the Dbt Cloud auth token is valid and has access to the job/account (test with a curl to the Discovery API)
- Check the jobId passed in options corresponds to an existing, successful job in the same account
- Read the inner errors[0].message for the actual API reason (auth, not found, validation) and fix accordingly
- Confirm the Dbt Cloud account/environment has the Discovery API/metrics enabled
- Upgrade the extension if the Discovery API schema changed
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch('https://cloud.getdbt.com/api/graphql/v2', {
method: 'POST',
headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: 'query { __typename }' })
});
if (!res.ok) throw new Error(`Dbt Cloud token/jobId check failed: ${res.status}`); Type guard
function hasGraphqlErrors(res) {
return Array.isArray(res?.errors) && res.errors.length > 0;
} Try / catch
try {
await dbt.loadMetricCubesFromDbtCloud(projectPath, { jobId, authToken });
} catch (e) {
if (e.message.startsWith("Can't fetch metrics from Dbt Cloud")) {
console.error('Dbt Cloud API error:', e.message); // inspect inner API message
} else { throw e; }
} Prevention
- Rotate and validate service tokens before deployment
- Verify jobId against the Dbt Cloud UI before configuring
- Confirm Discovery API access for the job's environment
- Wrap Dbt Cloud loads in retry-with-backoff for transient API issues
When it happens
Trigger: Calling loadMetricCubesFromDbtCloud with an invalid/expired Dbt Cloud API token, a jobId that doesn't exist or isn't accessible to the token, a GraphQL query error (e.g. metrics not exposed by the Discovery API for that job/account), or Dbt Cloud-side validation errors.
Common situations: Expired or rotated Dbt Cloud service tokens; wrong jobId in configuration; the job's environment lacking Discovery API access or the metrics feature; account/permission changes; Dbt Cloud API deprecations changing the schema the extension queries.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- ${response.status === 401 ? 'Unauthorized request' : 'Unexpe
- Failed to get access token: ${res.statusText}
- Databricks API error: ${res.statusText}
- SASL Failed with status ${status}: ${payload.toString('utf-8
- Variable "${value.name.value}" is not defined
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/f29c64559f26f2a8.
Report an issue: GitHub.