Skip to content

MEASURE(AGG(...)) causes 30-60s CPU spin before failing with 'Physical plan does not support logical expression' #10673

@hank-sq

Description

@hank-sq

Describe the bug

When a CubeSQL query contains a nested aggregate function inside MEASURE() — e.g., MEASURE(SUM(column)) — the query planner spins the CPU for 30-60 seconds before eventually returning an error. During this time, the single-threaded Cube process is completely blocked and cannot serve any other requests.

The correct syntax is either MEASURE(column) or SUM(column) — these are alternatives, not composable. However, instead of immediately rejecting the invalid nesting with a parse/validation error, Cube attempts to build a physical plan and gets stuck in an expensive planning loop.

Expected behavior

MEASURE(SUM(...)) (and similar nesting like MEASURE(COUNT(...)), MEASURE(AVG(...)), etc.) should be rejected immediately during SQL parsing or logical plan validation — ideally in under 100ms — with a clear error message like:

"Nested aggregate functions inside MEASURE() are not supported. Use MEASURE(column) or SUM(column), not MEASURE(SUM(column))."

Actual behavior

Cube spins the CPU for 30-60 seconds, blocking all concurrent requests, then returns:

This feature is not implemented: Physical plan does not support logical expression SUM(#ItemSales.sales_quantity)

The duration field in the error log confirms the excessive time (e.g., "duration": 64902 — nearly 65 seconds for a query that never reaches the database).

To Reproduce

Data model (YAML)

cubes:
  - name: ItemSales
    sql: "SELECT * FROM some_table"
    dimensions:
      - name: item_name
        sql: "{CUBE}.item_name"
        type: string
      - name: local_date
        sql: "{CUBE}.local_date"
        type: time
      - name: check_state
        sql: "{CUBE}.check_state"
        type: string
    measures:
      - name: sales_quantity
        sql: "CASE WHEN {CUBE}.transaction_type = 'SALE' THEN {CUBE}.quantity ELSE 0 END"
        type: sum

Query (via SQL API — REST or Postgres wire protocol)

SELECT
  ItemSales.item_name,
  MEASURE(SUM(ItemSales.sales_quantity)) AS total_quantity
FROM ItemSales
WHERE ItemSales.local_date >= '2026-01-11'
  AND ItemSales.local_date <= '2026-04-10'
  AND ItemSales.check_state = 'CLOSED_CHECK'
GROUP BY
  ItemSales.item_name
HAVING MEASURE(SUM(ItemSales.sales_quantity)) > 0
ORDER BY total_quantity DESC
LIMIT 20

Expected result

Immediate error (< 1 second) rejecting the query.

Actual result

~30-65 second hang, then:

{
  "error": "This feature is not implemented: Physical plan does not support logical expression SUM(#ItemSales.sales_quantity)"
}

Impact

This is an availability/DoS concern. Because Cube's query planner is single-threaded, a single MEASURE(SUM(...)) query blocks all other traffic for 30-60 seconds. In our production environment, a client submitted ~34 such queries in rapid succession, causing a sustained outage where no other requests could be served.

We've added a workaround on our API gateway layer to reject these patterns with a 400 before they reach Cube, but this should ideally be handled in Cube itself — both the immediate rejection and preventing the CPU spin.

Additional context

The table of valid aggregate functions from the Cube SQL API docs confirms that MEASURE(column) and SUM(column) are alternatives for sum-type measures. The docs do not document MEASURE(SUM(...)) as valid syntax, and the error confirms it isn't — the issue is purely that the rejection path is catastrophically slow.

Measure type Valid aggregate functions
sum MEASURE or SUM
count MEASURE or COUNT
avg MEASURE or AVG
min MEASURE or MIN
max MEASURE or MAX

None of these support nesting (e.g., MEASURE(SUM(...)), MEASURE(COUNT(...))).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions