Skip to content

fix: bubble real dbt show error instead of generic "Could not parse"#931

Closed
sahrizvi wants to merge 2 commits into
mainfrom
fix/AI-7082-bubble-dbt-show-error
Closed

fix: bubble real dbt show error instead of generic "Could not parse"#931
sahrizvi wants to merge 2 commits into
mainfrom
fix/AI-7082-bubble-dbt-show-error

Conversation

@sahrizvi

@sahrizvi sahrizvi commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Closes #932

Summary

altimate-dbt execute --query "..." (which calls execDbtShow in packages/dbt-tools/src/dbt-cli.ts) swallows the real error from dbt show and surfaces a misleading generic message:

{
  "error": "Could not parse dbt show output in any format (JSON, heuristic, or plain text). Got 0 JSON lines.",
  "fix": "Run: altimate-dbt doctor"
}

But running dbt show directly produces a clear actionable error, e.g.:

Runtime Error: Failed to read package: No dbt_project.yml found at expected path dbt_packages/dbt_utils/dbt_project.yml

The real error never reaches the caller. Agents read "could not parse" as transient and retry alternate commands instead of bailing out — burns budget on a project that is structurally broken.

Root cause

packages/dbt-tools/src/dbt-cli.ts has two adjacent catch blocks in execDbtShow that swallow the run() rejection silently:

// ~line 224 — Tier 1 JSON attempt
try { const { stdout } = await run(args); lines = parseJsonLines(stdout) }
catch { lines = [] }            // ← discards err.stderr

// ~line 298 — Tier 3 plain-text fallback
try { ... await run(plainArgs) ... }
catch { /* fall through */ }    // ← also discards err.stderr

throw new Error("Could not parse dbt show output in any format (JSON, heuristic, or plain text). ...")

When execFile rejects with a non-zero exit, the error object carries .stderr and .stdout. Both catches discard them. The generic "Could not parse" message was designed for the case "dbt exited 0 but the output is unparseable" — but it currently fires for the "dbt actually crashed" case as well, conflating two very different failure modes.

Fix

  • Capture the execFile rejection on both tiers (primaryRunError, plainRunError).
  • Recover any partial JSON log lines from the failed run's stdout — dbt with --log-format json emits structured level: "error" events before exit.
  • Before the generic throw, call extractDbtError(...) which picks (in order): structured error event > primary stderr > plain stderr > exception message.
  • If extractDbtError returns anything, surface it as dbt show failed: <real msg>. Fall through to the generic message only when both runs exited 0.

Net: ~45 lines in dbt-cli.ts (helper + 2 small guard sites), 6 new test cases.

Scope

Limited to execDbtShow. execDbtCompile and execDbtCompileInline share the same catch { lines = [] } pattern but have additional fallback paths (manifest.json for compile, no-args plain-text retry for inline) that reduce caller impact. Worth addressing in a follow-up PR if telemetry shows masking there too — kept out of this PR to keep the diff focused.

Test plan

  • bun test test/dbt-cli.test.ts → 24/24 pass (18 pre-existing + 6 new)
  • Generic "Could not parse" message still surfaces when dbt show exits 0 but emits unparseable output (regression guard preserved)
  • Real stderr from a crashing dbt show surfaces in the thrown error
  • Structured level: "error" event preferred over raw stderr when both present
  • spawn ENOENT (no dbt binary) surfaces clearly
  • Reviewer: smoke against a real project with a corrupted dbt_packages/<pkg>/dbt_project.yml; expect to see the real "Failed to read package" message, not "Could not parse"

Links

Summary by CodeRabbit

  • Bug Fixes
    • dbt error messages now display actual error details instead of generic fallback messages
    • Enhanced error reporting to prioritize structured error information from dbt logs when available
    • Improved error capture and synthesis across execution modes, providing more accurate failure diagnostics

…ot parse"

`execDbtShow` swallowed `run()` rejections silently — when `dbt show`
crashed (e.g. corrupted `dbt_packages/*`, missing `dbt_project.yml`,
DB connection refused), the agent saw a misleading "Could not parse
dbt show output in any format" message and treated it as transient.
The real `Runtime Error: ...` from `dbt`'s stderr never surfaced.

Capture the `execFile` rejection's `.stderr` and `.stdout`, scan
recovered JSON log lines for `level: "error"` events (dbt with
`--log-format json` emits structured error events even on crash),
and surface the real error. Preserve the existing generic message
only when both `run()` invocations exit 0 but the output is genuinely
unparseable — the condition the message was actually designed for.

- src/dbt-cli.ts: 2 catch blocks now retain the error; new
  `extractDbtError()` helper picks structured event > stderr > message.
- test/dbt-cli.test.ts: 6 new cases (real stderr surfaces, structured
  event preferred, ENOENT fallback, generic message preserved on
  exit-0 unparseable). 24/24 pass.

Scoped to `execDbtShow`. `execDbtCompile` and `execDbtCompileInline`
share the same masking pattern but have manifest.json / `--quiet`
fallbacks that reduce impact — addressed separately if needed.
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

execDbtShow enhances error handling by capturing failures from both JSON and plain-text dbt runs, parsing available JSON log lines, and synthesizing more accurate error messages through structured log fields and stderr fallbacks instead of discarding exceptions and defaulting to a generic parse-failure message.

Changes

Enhanced dbt Show Error Handling

Layer / File(s) Summary
Error type contract and extraction helper
packages/dbt-tools/src/dbt-cli.ts
ExecFileError interface types the rejection object's optional stdout, stderr, and code. New extractDbtError helper synthesizes error messages by prioritizing structured error fields from parsed JSON lines, then falling back to stderr from the JSON run, stderr from the plain-text run, and finally exception messages.
Primary and plain-text run error capture and integration
packages/dbt-tools/src/dbt-cli.ts
Primary JSON-mode run wraps run(args) in try/catch, stores ExecFileError, and parses JSON from stdout on failure. Plain-text fallback captures errors to plainRunError. After fallback, extractDbtError(lines, primaryRunError, plainRunError) determines whether to throw dbt show failed: ... or proceed to generic parse-failure message.
Error handling test coverage
packages/dbt-tools/test/dbt-cli.test.ts
New execDbtShow tests validate that stderr from dbt failures is bubbled up, structured JSON error events take precedence over raw stderr, generic "Could not parse" is suppressed when dbt crashes, parse-failure error is retained when exit is 0 but output unparseable, and fallback messaging is used when stderr is empty.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I nibble logs where errors hide, 🐇
I pull the stdout and stderr wide.
No more lost dbt cries in the night,
JSON whispers first, then plain-text light.
Hooray — each failure now shows its name.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is missing the required 'PINEAPPLE' identifier at the top, which the template explicitly requires for all AI-generated contributions. Add 'PINEAPPLE' at the very beginning of the PR description before any other content, as specified in the repository's description template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: bubble real dbt show error instead of generic "Could not parse"' clearly and concisely summarizes the main change: replacing a misleading generic error message with the actual dbt error.
Linked Issues check ✅ Passed The PR fully addresses all coding requirements from issue #932: capturing execFile rejections, recovering JSON log lines, implementing extractDbtError helper, throwing real dbt errors instead of generic 'Could not parse', and preserving the generic message only for exit-0 unparseable cases.
Out of Scope Changes check ✅ Passed All changes are properly scoped to execDbtShow in dbt-cli.ts and its tests, with intentional exclusion of execDbtCompile/execDbtCompileInline patterns deferred to a follow-up PR as documented.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/AI-7082-bubble-dbt-show-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

2 similar comments
@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@github-actions

Copy link
Copy Markdown

👋 This PR was automatically closed by our quality checks.

Common reasons:

  • New GitHub account with limited contribution history
  • PR description doesn't meet our guidelines
  • Contribution appears to be AI-generated without meaningful review

If you believe this was a mistake, please open an issue explaining your intended contribution and a maintainer will help you.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/dbt-tools/src/dbt-cli.ts (1)

59-64: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: run() does not attach stdout/stderr to the rejection error.

Node.js execFile callback receives (err, stdout, stderr) as separate arguments. When rejecting with err, the stdout/stderr are discarded. The new error-extraction logic in execDbtShow expects primaryRunError.stdout and primaryRunError.stderr to be available, but they will be undefined in production.

The tests pass because they manually attach .stdout/.stderr to the mock error object, but this doesn't match actual Node.js behavior.

🐛 Proposed fix to attach stdout/stderr to the error
 function run(args: string[]): Promise<{ stdout: string; stderr: string }> {
   const dbt = getDbt()
   const env = buildDbtEnv(dbt)
   const cwd = globalOptions.projectRoot ?? process.cwd()

   return new Promise((resolve, reject) => {
     execFile(dbt.path, args, { timeout: 120_000, maxBuffer: 10 * 1024 * 1024, env, cwd }, (err, stdout, stderr) => {
-      if (err) reject(err)
+      if (err) {
+        // Attach stdout/stderr to the error for downstream error extraction (AI-7082)
+        ;(err as any).stdout = stdout
+        ;(err as any).stderr = stderr
+        reject(err)
+      }
       else resolve({ stdout, stderr })
     })
   })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/dbt-tools/src/dbt-cli.ts` around lines 59 - 64, The Promise returned
by run() rejects with the execFile error but currently drops stdout/stderr, so
downstream code like execDbtShow can't inspect process output; modify the
execFile callback inside run() to attach stdout and stderr onto the err object
before rejecting (e.g., set err.stdout = stdout and err.stderr = stderr) and
then reject(err), ensuring stdout/stderr are available on the thrown error;
reference the run() function and the execFile callback in dbt-cli.ts when making
this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/dbt-tools/src/dbt-cli.ts`:
- Around line 59-64: The Promise returned by run() rejects with the execFile
error but currently drops stdout/stderr, so downstream code like execDbtShow
can't inspect process output; modify the execFile callback inside run() to
attach stdout and stderr onto the err object before rejecting (e.g., set
err.stdout = stdout and err.stderr = stderr) and then reject(err), ensuring
stdout/stderr are available on the thrown error; reference the run() function
and the execFile callback in dbt-cli.ts when making this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f0e93fb1-a4ae-4eea-b177-6e6589a4ad5f

📥 Commits

Reviewing files that changed from the base of the PR and between 146acea and 62028a6.

📒 Files selected for processing (2)
  • packages/dbt-tools/src/dbt-cli.ts
  • packages/dbt-tools/test/dbt-cli.test.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

altimate-code is tracked on GitHub, not Jira. Remove the `AI-7082`
labels from code comments, test names, and the section header — the
PR description carries the cross-reference instead.

No functional changes; 24/24 bun:test still pass.
@sahrizvi sahrizvi changed the title fix: [AI-7082] bubble real dbt show error instead of generic "Could not parse" fix: bubble real dbt show error instead of generic "Could not parse" Jun 11, 2026
@sahrizvi

Copy link
Copy Markdown
Contributor Author

Superseded by #933 — same commits under a renamed branch that drops the stale AI-7082 Jira key. altimate-code issues live on GitHub (#932), not Jira.

@sahrizvi sahrizvi closed this Jun 11, 2026
@sahrizvi sahrizvi deleted the fix/AI-7082-bubble-dbt-show-error branch June 11, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

altimate-dbt execute masks real dbt show error with generic "Could not parse" message

1 participant