The error pipeline: one failure, every surface, no garbling
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
A sql plugin's "connection refused" crosses five boundaries — plugin → wire → host classification → history → CLI/LSP/JSON — and the garbling failure mode at every hop is the same: flattening structure into a string too early, then wrapping it again ("step x: plugin sql: step x: rpc error: ..."). This issue records the rule that prevents it and the two pieces that complete it. Companion to #181's author-time diagnostics tiers; this is the runtime half.
The rule: structure travels, text is rendered last
Every hop passes the structured form — kind, retryability, retry-after, message, source — and only the final surface renders text (the #164 discipline applied to failures). What already holds, mostly from this week: the SDK constructors are the plugin's typed vocabulary (Unavailable/Conflict/OutcomeUnknown/UnavailableAfter…); they cross the wire as a connect code plus a typed ExecuteResponse detail, never string convention; the host classifies from the ORIGINAL error before scrubbing (the #160 fix — redaction can no longer destroy classification); error text is spelled identically on both drivers (invariant, shared cases); machine surfaces render from structure.
Gap 1: a round-trip conformance test plugins inherit for free
In the SDK: classified error → wire → host TaskError → rendered text and JSON, asserting kind/retryability/hint survive and the message appears EXACTLY once (double-prefixing is garbling too). A plugin author only chooses a constructor; the conformance test is what keeps "my errors read correctly everywhere" true as plugins multiply. Containment shapes included (%v/%+v/%#v/%s on the error, a struct holding it, a slice) so the secrets rules ride the same test.
Gap 2: source positions on runtime failures
Today a runtime failure names its step id; the file position exists only at compile time. If the compiled spec carries a compact, optional, bytes-bounded source map (step id → file/line/column), then flow get on a failed run can say: step "lookup" (workflow.yaml:23): sql: connection refused — retryable, next attempt in 30s. An agent reading the JSON gets the position machine-readably — production failure straight back to the editor line. One-artifact philosophy: the position was known once, at compile; carrying it forward beats every consumer re-deriving it. Bounds: the map counts against CheckSpecSize; positions are advisory (absent on hand-built specs, which is fine — invariant 10 add-only).
Burden placement
Plugin authors: choose a constructor. Host, once: classification, scrubbing order, both-driver text, JSON shape, position attachment. The conformance test enforces the contract. sql (#181) is the first beneficiary; git's Conflict classification is the existing proof the vocabulary works end to end (a Flowfile can dispatch on "someone else pushed first" vs "this broke").
Sequencing: both pieces Sonnet-sized, after the current wave; the source map wants a slice of its own (proto field + parser emission + get/watch rendering + LSP jump-to-step).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Trace the SDK constructors through wire encoding, host classification, and the final CLI/LSP/JSON renderers. Establish the round-trip conformance test first, then inspect compiled-spec handling for the optional source map and its flow get/watch and LSP consumers. Done means structured errors survive every boundary without garbling, and source positions remain bounded, optional, and machine-readable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend, cli, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100