Skip to content

fix: SQL error when clicking search on a log while viewing trace - #2825

Open
karl-power wants to merge 1 commit into
mainfrom
karl/search-log-from-trace
Open

fix: SQL error when clicking search on a log while viewing trace#2825
karl-power wants to merge 1 commit into
mainfrom
karl/search-log-from-trace

Conversation

@karl-power

@karl-power karl-power commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Opening a trace and clicking a Search action on a log event from the waterfall threw a SQL error. The Search actions built a where clause from the log's columns but generated a /search URL that kept the searched (traces) source, so log columns were queried against the trace table. The same bug existed in the mirror direction (span selected from a Logs search) and for cross-source pushed frames (e.g. a span-link "View Trace" hop). Manually switching to the logs view first worked, confirming only the source binding was wrong.

Screenshots or video

Bug repro:

Screen.Recording.2026-08-06.at.14.25.08.mov

How to test on Vercel preview

Preview routes: /search

Steps:

Traces search → open trace → click log event → Search now lands on the logs source with the where clause applied, no SQL error.

References

  • Linear Issue: Closes HDX-5040
  • Related PRs:

@changeset-bot

changeset-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b2487a7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview Aug 6, 2026 1:47pm
hyperdx-storybook Ready Ready Preview Aug 6, 2026 1:47pm

Request Review

@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔵 Tier 2 — Low Risk

Small, isolated change with no API route or data model modifications.

Why this tier:

  • Standard feature/fix — introduces new logic or modifies core functionality

Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns.
SLA: Resolve within 4 business hours.

Stats
  • Production files changed: 3
  • Production lines changed: 64 (+ 108 in test files, excluded from tier calculation)
  • Branch: karl/search-log-from-trace
  • Author: karl-power

To override this classification, remove the review/tier-2 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR fixes cross-source searches from trace and row detail panels by rebinding generated search URLs to the selected event’s source and disabling source-specific filter and column actions when schemas differ.

  • Adds a shared helper for deriving source-aware row-side-panel context.
  • Applies the derived context to selected trace events and cross-source panel navigation.
  • Adds regression coverage for log events selected from traces and same-source spans.
  • Adds the application patch changeset and updates Knip exclusions for Stryker tooling.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/app/src/components/DBRowSidePanel.tsx Introduces centralized source-aware context derivation and applies it to resolved leaf rows.
packages/app/src/components/DBTracePanel.tsx Provides selected trace or log events with context rebound to their resolved source.
packages/app/src/components/tests/DBTracePanel.test.tsx Verifies cross-source URL generation and gating of incompatible filter actions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Search source context] --> B[Open trace or row detail]
  B --> C[Resolve selected event source]
  C --> D[Derive row-side-panel context]
  D --> E[Generate Search URL with event source]
  D --> F{Same source?}
  F -->|Yes| G[Retain filter and column actions]
  F -->|No| H[Disable source-specific actions]
Loading

Reviews (2): Last reviewed commit: "fix: SQL error when clicking search on a..." | Re-trigger Greptile

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 271 passed • 1 skipped • 1066s

Status Count
✅ Passed 271
❌ Failed 0
⚠️ Flaky 1
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

@karl-power
karl-power force-pushed the karl/search-log-from-trace branch from 0d08bff to b2487a7 Compare August 6, 2026 13:43
Comment thread knip.json
Comment on lines 43 to 51
],
"ignoreBinaries": ["make", "migrate"],
"ignoreBinaries": ["make", "migrate", "stryker"],
"ignoreDependencies": [
"@dotenvx/dotenvx",
"concurrently",
"dotenv",
"babel-plugin-react-compiler"
"babel-plugin-react-compiler",
"@stryker-mutator/core"
],

@karl-power karl-power Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Deep Review

Method note: git, gh, and network access were all unavailable in this environment (bubblewrap sandbox failure on every shell invocation), so no git diff could be computed. Scope was reconstructed by reading the working tree at HEAD and confirmed against the new tests in DBTracePanel.test.tsx. Findings cite verified line numbers, but removed lines were not visible — a claim that something is newly introduced vs. pre-existing is lower confidence than usual and is called out per finding where it matters.

✅ No critical issues found. The core fix is sound: deriveRowSidePanelContextForSource threads args.source ?? source correctly through nested derivations, and the cross-source /search URL branch that omits select/filters was traced end-to-end and does fall back to the target source's defaultTableSelectExpression rather than producing an invalid query. The issues below are incomplete coverage of the same bug class, not defects in the mechanism itself.

🟡 P2 -- recommended

  • packages/app/src/components/DBTracePanel.tsx:376 -- selectedSpanSource returns traceSourceData whenever selectedSpan.type === SourceKind.Log but logSourceData is falsy, re-binding a log row to the trace table — the exact mismatch this change sets out to eliminate.
    • Fix: Make the log branch total — if (selectedSpan.type === SourceKind.Log) return logSourceData ?? null; — since the render guard at :505-507 already hides the panel when selectedSpanSource is null.
    • correctness, adversarial, julik-frontend-races, testing
  • packages/app/src/components/DBTracePanel.tsx:311 -- the persisted eventRowWhere selection is gated only on traceId, so a WHERE clause built from one correlated-log source is replayed against a different one after the "Correlated logs" picker changes.
    • Fix: Stamp the owning source id onto the selection in selectSpan alongside traceId and require it to match in the read-time gate.
    • julik-frontend-races, adversarial, correctness
  • packages/app/src/components/DBRowSidePanel.tsx:124 -- the helper spreads ...parentContext and never assigns the source argument to the returned context's source field, so a context produced by this function misreports the source it was derived for.
    • Fix: Assign source explicitly on the returned object, narrowing to the field's TLogSource | TTraceSource type since the parameter is the wider TSource.
    • kieran-typescript, maintainability, correctness
  • packages/app/src/components/DBRowSidePanel.tsx:129 -- the gate overwrites onPropertyAddClick, displayedColumns, and toggleColumn with undefined irrecoverably, so a second derivation that correctly computes sameSource === true has nothing left to restore and filter/column actions stay hidden on rows that legitimately belong to the searched source.
    • Fix: Carry the searched source's callbacks through under a separate key and re-expose them when source.id === parentContext.source.id instead of destroying them at each level.
    • adversarial
  • packages/app/src/DBSearchPage.tsx:1703 -- generateSearchUrl writes raw values into URLSearchParams while the landing page reads where/select through parseAsStringEncoded, which applies a second decodeURIComponent, so any value containing a %XX sequence silently arrives mangled; this is pre-existing but the new cross-source branch inherits it.
    • Fix: Pre-encode where and select with encodeURIComponent before qParams.append, or serialize via createSerializer(queryStateMap) so writer and reader share one encoding contract.
    • adversarial
  • packages/app/src/components/DBRowSidePanel.tsx:597 -- the cross-source pushed-frame call site and the exported deriveRowSidePanelContextForSource helper itself have no test; no DBRowSidePanel test file exists anywhere in the repo.
    • Fix: Add packages/app/src/components/__tests__/DBRowSidePanel.test.tsx covering the helper's sameSource true/false branches and a render-level test of the "View Trace" / span-link push path.
    • testing, maintainability, kieran-typescript, api-contract
  • packages/app/src/DBSearchPage.tsx:1713 -- the cross-source URL branch that is the root-cause fix is unreachable from any test because generateSearchUrl is defined inline in a useCallback and never exported; the new tests only assert against a jest.fn() stand-in.
    • Fix: Extract the URL construction into an exported pure helper alongside buildSavedSearchNavigationUrl and assert that the cross-source branch emits source and omits select/filters.
    • testing, adversarial, correctness, project-standards
🔵 P3 nitpicks (5)
  • packages/app/src/components/DBRowSidePanel.tsx:88 -- source?: TSource is optional and sameSource treats a missing parentContext.source as same-source, so a future provider that reads the context directly compiles cleanly and silently reverts to the pre-fix behavior.
    • Fix: Make source required on the callback signature, or expose a useRowSearchUrl(source) hook that consumers must go through.
    • maintainability, kieran-typescript, api-contract, correctness, adversarial
  • packages/app/src/components/DBRowSidePanel.tsx:97 -- generateChartUrl, dbSqlRowTableConfig, and shareUrl are spread through the derivation untouched while their sibling generateSearchUrl is rebound; currently dormant because no reachable provider sets generateChartUrl and dbSqlRowTableConfig is nulled by hasActiveStacks.
    • Fix: Either gate these three on sameSource too or add a comment recording why they are deliberately left source-naive.
    • api-contract, maintainability, adversarial, correctness
  • packages/app/src/components/DBTracePanel.tsx:49 -- importing the context and helper from DBRowSidePanel.tsx, which itself imports DBTracePanel, closes a module cycle that already forced a documented jest.requireActual workaround in the new test.
    • Fix: Move RowSidePanelContext and deriveRowSidePanelContextForSource into a standalone module both files import.
    • maintainability
  • packages/app/src/DBSearchPage.tsx:1711 -- the same function now emits two structurally different /search URL shapes and nothing records that an absent select/filters is an intentional "use the target source's defaults" signal.
    • Fix: Add a short comment at the branch explaining the omission is deliberate so a later change does not "restore" the params.
    • api-contract
  • packages/app/src/components/DBRowSidePanel.tsx:95 -- RowSidePanelContextProps now carries two differently-typed fields named source (TSource inside generateSearchUrl's parameter, TLogSource | TTraceSource at the top level).
    • Fix: Rename the callback parameter field to targetSource.
    • kieran-typescript

Reviewers (10): correctness, adversarial, testing, maintainability, kieran-typescript, julik-frontend-races, api-contract, project-standards, agent-native, learnings-researcher.

Testing gaps:

  • No test exercises the real two-level derivation chain — the new tests hand-build an already-derived RowSidePanelContext around DBTracePanel, bypassing DBRowSidePanel's own derivation at :601.
  • The mirror direction (context source = log source, selected event = trace span) is not covered; the second new test is a same-source case, not the reverse cross-source case.
  • selectedSpanSource's fallback branch is never hit — beforeEach always populates both trace-source and log-source.
  • No round-trip test navigates a generated URL back into the search page to confirm the where clause survives parseAsStringEncoded.
  • Root AGENTS.md requires a changeset in .changeset/ for user-facing changes to @hyperdx/app; the directory could not be enumerated in this environment, so confirm one accompanies this change before merge.
  • Agent-native parity verified as a non-issue: the MCP tools in packages/api/src/mcp/ take sourceId explicitly and clickstack_trace_waterfall already binds correlated logs to source.logSourceId, so no mirror fix is needed there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/tier-2 Low risk — AI review + quick human skim

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants