cube-js/cube · error · UserError
Pre-aggregation YAML must be a map/object
Error message
Pre-aggregation YAML must be a map/object
What it means
convertYaml parses a pre-aggregation YAML document with the yaml library and requires the root node to be a map. If the document is empty, a scalar, or a sequence, it throws UserError 'Pre-aggregation YAML must be a map/object' because pre-aggregation definitions must be key/value maps keyed by rollup name.
Source
Thrown at packages/cubejs-schema-compiler/src/compiler/converters/CubePreAggregationConverter.ts:89
t.objectExpression([t.objectProperty(t.identifier(preAggregationName), preAggregationNode)])
)
);
} else {
(<t.ObjectExpression>anchor).properties.push(
t.objectProperty(t.identifier(preAggregationName), <t.ObjectExpression>preAggregationNode)
);
}
}
protected convertYaml(cubeDefSet: YamlSet) {
const { preAggregationName, code } = this.preAggregationDefinition;
const { cubeDefinition } = cubeDefSet;
const preAggDoc = YAML.parseDocument(code);
const preAggNode = preAggDoc.contents;
if (!preAggNode || !isMap(preAggNode)) {
throw new UserError('Pre-aggregation YAML must be a map/object');
}
const preAggsPair = cubeDefinition.items.find(
(pair: Pair) => isScalar(pair.key) && (pair.key.value === 'pre_aggregations' || pair.key.value === 'preAggregations')
);
if (preAggsPair) {
const seq = preAggsPair.value;
if (!YAML.isSeq(seq)) {
throw new UserError('\'pre_aggregations\' must be a sequence');
}
const exists = seq.items.some(item => {
if (isMap(item)) {
const namePair = item.items.find(
(pair: Pair) => isScalar(pair.key) && pair.key.value === 'name'
);
return namePair && isScalar(namePair.value) && namePair.value.value === preAggregationName;View on GitHub (pinned to 7d981676b3)
Solutions
- Make the YAML root a mapping: pre_aggregations: - name: ... structure (or a map of pre-aggregation names to definitions)
- Check the file is not empty or comment-only
- Wrap list content under a top-level key instead of a root-level sequence
- Validate the YAML parses to an object: YAML.parseDocument(code).contents is a YAMLMap
Example fix
# before
- measures:
- orders.count
# after
pre_aggregations:
- name: main
measures:
- orders.count Defensive patterns
Strategy: validation
Validate before calling
const YAML = require('yaml');
function assertYamlIsMap(code) {
const doc = YAML.parseDocument(code);
if (!doc.contents || !YAML.isMap(doc.contents)) {
throw new Error('Pre-aggregation YAML must be a root-level map/object');
}
} Try / catch
try {
converter.convert(astByCubeName);
} catch (e) {
if (e.message === 'Pre-aggregation YAML must be a map/object') {
console.error('Check the pre-aggregation YAML file: root must be a mapping, not a list or empty doc');
}
} Prevention
- Validate YAML files with a linter before committing
- Never leave pre-aggregation YAML files empty or comment-only
- Keep definitions nested under pre_aggregations, never at document root
When it happens
Trigger: Passing YAML that is an empty document, a bare list of measures, or a scalar string as the pre-aggregation code to CubePreAggregationConverter when the cube definition came from YAML.
Common situations: Hand-editing YAML and deleting the top-level mapping, generating YAML from tools that emit sequences, or a file that is empty/only comments so the parsed root is null.
Related errors
- Invalid Job query format: ${error.message || error.toString(
- Cannot parse selector date range ${selector.dateRange}
- Pre-aggregation definition is malformed
- 'pre_aggregations' must be a sequence
- Can't parse date: '${from}'
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/adfe7e02c88266b3.
Report an issue: GitHub.