Skip to content

fix: wrap timeseries rows in Druid-era envelope for UI consumers#5

Merged
mbradley merged 1 commit into
mainfrom
fix/timeseries-response-shape
Apr 22, 2026
Merged

fix: wrap timeseries rows in Druid-era envelope for UI consumers#5
mbradley merged 1 commit into
mainfrom
fix/timeseries-response-shape

Conversation

@mbradley
Copy link
Copy Markdown
Member

Summary

Fixes the long-standing Timeseries chart crash in Osprey UI. The ClickHouse adapter returned flat rows {timestamp, count} (or {timestamp, <dim1>, <dim2>, ...} when aggregation_dimensions are set), but two consumers expect the Druid-era envelope {timestamp, result: {...}}:

  • UI: osprey_ui/src/components/timeseries/Timeseries.tsx:108 reads point.result.count. With the flat shape, point.result is undefined, so reading .count on it crashes the component (observed: Uncaught TypeError: Cannot read properties of undefined (reading 'count')).
  • Python: osprey_worker/src/osprey/worker/ui_api/osprey/views/entities.py:64 reads timeseries_result[0]['result']. With the flat shape, there is no result key.

The TimeseriesResult TypeScript interface already declares the envelope:

export interface TimeseriesResult {
  timestamp: string;
  result: {
    count: number;
    [key: string]: number;
  };
}

which is designed to carry either a plain count or the per-dimension aggregations the query can emit.

Fix

Reshape rows inside TimeseriesClickHouseQuery.execute() so both consumers see the expected envelope. Transform verified against both response cases:

Input row Output
{timestamp, count: 84} {timestamp, result: {count: 84}}
{timestamp, ns: 5, ai: 7} {timestamp, result: {ns: 5, ai: 7}}

Reproduction (pre-fix)

  1. Port-forward osprey-ui :5002 and osprey-ui-api :5004 in staging.
  2. Open http://localhost:5002/, run any query that returns data (e.g. Kind > 0 over Last Day).
  3. Console: Uncaught TypeError: Cannot read properties of undefined (reading 'count') with a stack at TimeseriesQueryViewAppRouter. Chart shows 'No data available' overlay.

Verification

  • Transform logic unit-tested against both input shapes (see commit message).
  • Full end-to-end verification after merge + staging sync.

Scope

Read-side only. No rule, schema, or enforcement-path changes. Matches the pattern flagged in prior osprey-staging notes as the remaining Druid→ClickHouse shape adapter gap.

The ClickHouse timeseries adapter returned rows as {timestamp, count}
(or {timestamp, <dim1>, <dim2>, ...} when aggregation_dimensions are
set). Two consumers expect the Druid-era shape {timestamp, result: {...}}:

- osprey_ui Timeseries.tsx:108 reads point.result.count — currently
  crashes with 'Cannot read properties of undefined (reading count)'
  whenever the chart has data to render.
- views/entities.py:64 reads timeseries_result[0]['result'] — silently
  KeyError or wrong-shape depending on context.

Both consumers reflect the TimeseriesResult type in
osprey_ui/src/types/QueryTypes.tsx, which declares:
  result: { count: number; [key: string]: number }
— designed to carry either a plain count or the per-dimension
aggregation this query emits when aggregation_dimensions is populated.

Reshape the rows inside TimeseriesClickHouseQuery.execute() so both
consumers see the expected envelope. Transform verified against both
response cases (plain count, aggregation dimensions).
@mbradley mbradley requested a review from dcadenas April 21, 2026 17:02
@mbradley
Copy link
Copy Markdown
Member Author

thanks @dcadenas, i keep pulling you in because this sits right at the intersection of T&S and devops, and you happen to sit at the intersection of devops and a lot of things. really appreciate the review bandwidth.

Copy link
Copy Markdown

@dcadenas dcadenas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve. The reshape matches the {timestamp, result: {...}} shape the UI and entities.py consumers expect, and the inline comment points at both call sites so future readers can verify.

@mbradley mbradley merged commit 7dfaf03 into main Apr 22, 2026
6 checks passed
@mbradley mbradley deleted the fix/timeseries-response-shape branch April 22, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants