feat: emit pipeline/connector instance_not_found ConduitError codes#2530
Merged
Conversation
Step 4 of the structured-error rollout: two more error sources now emit ConduitError codes instead of bare sentinels, following the pattern from connector.plugin_not_found (#2528). - pipeline.ErrInstanceNotFound, raised in pipeline.Service.Get (the sole choke point — Update/Delete/AddConnector/etc. all call Get internally), now wraps with a new code pipeline.instance_not_found (codes.NotFound) and a suggestion to run `conduit pipelines list`. - connector.ErrInstanceNotFound, raised in connector.Service.Get (same choke-point property), wraps with connector.instance_not_found (codes.NotFound) and a suggestion to run `conduit connectors list`. Both sentinels remain in the error chain via conduiterr.Wrap, so existing errors.Is(err, ErrInstanceNotFound) checks throughout pkg/provisioning, pkg/orchestrator, and pkg/http/api/status are unaffected — verified by running those suites plus pkg/lifecycle(-poc). Tests augment TestService_GetInstanceNotFound in both packages to assert the sentinel Is-check AND the new code + non-empty Suggestion via conduiterr.Get. processor.ErrInstanceNotFound is a separate, un-migrated error source (pkg/processor/service.go) — left out of scope for this step to keep the blast radius tight; it's a natural next candidate. Design: docs/design-documents/20260705-conduit-error-and-structured-output.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
devarismeroxa
added a commit
that referenced
this pull request
Jul 6, 2026
…gin registries) (#2532) Finishes the not-found migrations begun in the connector-plugin (#2528) and pipeline/connector-instance (#2530) PRs: - processor.instance_not_found (CodeProcessorNotFound, pkg/processor/codes.go): Service.Get now wraps ErrInstanceNotFound with the code + a suggestion — the single choke point every processor method routes through. - processor.plugin_not_found (CodeProcessorPluginNotFound): the builtin and standalone processor registries now emit the code when a plugin/version is missing, mirroring the connector builtin registry from #2528. - connector.plugin_not_found: the standalone connector registry now emits the code too, completing the connector plugin-not-found set (builtin was #2528). All sites keep the original sentinel in the chain via conduiterr.Wrap (errors.Is(err, ErrInstanceNotFound) / plugin.ErrPluginNotFound unaffected; invariant noted at each site). Purely additive. Test: TestService_Get_Fail asserts both the sentinel Is-check and the new code + suggestion. Existing registry/service suites pass unchanged. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 4 of the structured-error rollout (follows #2528, #2527, #2524). Migrates two more error sources to emit
ConduitErrorcodes, exercising the API boundary wired in #2527, following the exact pattern used forconnector.plugin_not_found.pipeline.ErrInstanceNotFound— raised inpipeline.Service.Get, the sole construction site (every other method —Update,Delete,AddConnector,AddProcessor, etc. — callsGetinternally, so this single choke point covers all not-found paths). Now wraps with a new codepipeline.instance_not_found(codes.NotFound, registered in newpkg/pipeline/codes.go) and a suggestion to runconduit pipelines list.connector.ErrInstanceNotFound— same treatment inconnector.Service.Get(same choke-point property). New codeconnector.instance_not_found(codes.NotFound, registered in newpkg/connector/codes.go), suggestion to runconduit connectors list.Both sentinels remain in the error chain via
conduiterr.Wrap(code, msg, sentinel), so this is additive and backward-compatible: any error that is not one of these two sentinels is unaffected, and existingerrors.Is(err, ErrInstanceNotFound)checks acrosspkg/provisioning,pkg/orchestrator, andpkg/http/api/statuscontinue to hold unchanged — no behavior change for consumers that only checkerrors.Is. Consumers reading the error throughconduiterr.Getnow additionally get a stable machine-actionable code + suggestion.Deliberately out of scope:
processor.ErrInstanceNotFound(pkg/processor/service.go) is a separate, un-migrated error source with the same shape — left for a follow-up PR to keep this change's blast radius tight (single choke point in each of two packages, not a third).Self-review (adversarial pass, per CLAUDE.md)
conduiterr.Wrap's "inner ConduitError code wins" branch doesn't fire here — both sentinels are plaincerrors.New(...)values, not existing*ConduitErrors, so the new code is always the one that lands. Confirmed viaWrap'scerrors.As(cause, &inner)check.instance_not_found— each reason (pipeline.instance_not_found,connector.instance_not_found) is registered exactly once.Get-produced message text (old:"pipeline instance not found (ID: %s)", new:"pipeline %q not found") — everywhere else useserrors.Is, not string comparison, so the wording change is safe.pkg/http/api/status/status_test.go's existingTestPipelineError/TestConnectorError/TestNonConduitErrorUnchangedcases pass the bare sentinel directly intoPipelineError/ConnectorError(not throughService.Get), so they're unaffected by this change and remain green as regression coverage for the "non-ConduitError" fallback path.Test plan
go build ./...cleango test ./pkg/pipeline/... ./pkg/connector/... ./pkg/http/api/status/... -count=1— greengo test ./pkg/orchestrator/... ./pkg/provisioning/... ./pkg/lifecycle/... ./pkg/lifecycle-poc/... -count=1— green (confirms no downstreamerrors.Isregressions)golangci-lint run ./pkg/pipeline/... ./pkg/connector/...(v2.12.2) — 0 issuesTestService_GetInstanceNotFoundaugmented in bothpkg/pipelineandpkg/connectorto assert the sentinelerrors.Ischeck ANDconduiterr.Get(err)returns the new code with a non-emptySuggestion, mirroring theconnector.plugin_not_foundtest augmentationDesign:
docs/design-documents/20260705-conduit-error-and-structured-output.md🤖 Generated with Claude Code
https://claude.ai/code/session_01Tapg9dLWXKMZJoL65R24vd