cube-js/cube · error · UserError

'pre_aggregations' must be a sequence

Error message

'pre_aggregations' must be a sequence

What it means

Cube's YAML data model converter requires the top-level 'pre_aggregations' (or 'preAggregations') key to hold a YAML sequence (list) of pre-aggregation definitions. This library throws when the value under that key is a scalar or a map instead of a list, because it iterates seq.items to extract per-pre-aggregation names.

Source

Thrown at packages/cubejs-schema-compiler/src/compiler/converters/CubePreAggregationConverter.ts:99

  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;
        }
        return false;
      });

      if (exists) {
        throw new UserError(`Pre-aggregation '${preAggregationName}' is already defined`);
      }

      seq.items.push(preAggNode);
    } else {

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Rewrite pre_aggregations as a YAML sequence: each pre-aggregation starts with `- ` under the key
  2. Check indentation — pre_aggregations must be a sibling key of the cube, and its items indented with '- '
  3. If migrating from JS schema, remember YAML names go inside each item's 'name:' field, not as map keys

Example fix

# before
pre_aggregations:
  main:
    measures: [visitors.count]
# after
pre_aggregations:
  - name: main
    measures:
      - visitors.count
Defensive patterns

Strategy: validation

Validate before calling

function assertPreAggregationsIsList(cube) {
  const v = cube.pre_aggregations ?? cube.preAggregations;
  if (v != null && !Array.isArray(v)) {
    throw new Error("'pre_aggregations' must be a list of pre-aggregation objects");
  }
}

Type guard

const isPreAggSeq = (v) => Array.isArray(v) || (v && typeof v.items === 'object');

Try / catch

try {
  converter.convert(cubeDef);
} catch (e) {
  if (e.message.includes("'pre_aggregations' must be a sequence")) {
    console.error('Fix YAML: pre_aggregations items must start with "- "');
  }
  throw e;
}

Prevention

When it happens

Trigger: Defining pre_aggregations as a YAML mapping (e.g. `pre_aggregations:\n main: ...`), as a scalar string, or with wrong indentation so the parsed node is not a YAMLSeq, while converting a YAML schema file via CubeSchemaConverter.convertYaml.

Common situations: Hand-written YAML data models where pre_aggregations was indented as a map instead of a list item; copying JS-style named pre-aggregations (`main: {...}`) into YAML without the `- ` list prefix; tabs/indentation errors making the parser see a map.

Related errors


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