Repository navigation
fix(server): client-safe error bodies, accurate status codes and clearer OTel modals - #75
Merged
muzamilkm merged 5 commits intoSep 30, 2026
Conversation
ubaidkhalidarbisoft
approved these changes
Sep 30, 2026
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
Follows up the findings from the production deletion-guardrail run (after #74). API error responses no longer carry the errors package's internals, every error returns a status code that matches what actually went wrong, and the project delete and Claude Code OTel confirmation modals are clearer.
Client-safe error bodies
The run found error bodies that were accurate but not written for users: every message ended in the status code (
… (409)),causesexposed the internal wrap chain (for exampleerror executing delete hook for plugin claude_otel), and some bodies were built fromerr.Error(), which renders the whole chain, including stack frames whenENABLE_STACKTRACEis set.messageis the top-level message only, without the(NNN)suffix. The status is already the response's status code. Logs are unchanged and still carry the full chain and codes.causesis no longer filled from the error chain. The Config UI never read it. The field stays onApiBodybecause the GitHub multi-token test fills it itself.messageto the safe message, so the blueprint and project list is kept buterr.Error()no longer reaches the client. The helpers themselves are untouched.an unexpected error occurred. Its message is often a converted SQL, driver or runtime error. Every other status keeps its text.at least one pipeline is running (409)at least one pipeline is runningerror deleting project (400), with the real reason only incausesrevoke the active Claude Code OTel connection before deleting its final project placementbad request body formatKey: 'JiraConn.Endpoint' Error:Field validation for 'Endpoint' failed on the 'required' tag…Endpoint is required; AuthMethod is requiredan unexpected error occurredStatus classification
Test Connection statuses
Test Connection passed the remote service's status straight through, so a rejected Jira token made DevLake itself answer 401, and a wrong Jira endpoint answered 404.
WrapTestConnectionErrRespnow remaps the status and keeps the message, so users still see why the check failed:Please check your credential.Failed to resolve DNS.Failed to connect.This applies to every plugin whose Test Connection uses that wrapper, including GitHub and Jira.
Claude Code OTel: 409 for state conflicts
These used to return 400 and are now 409, matching DevLake's own 409 for "referenced by blueprints":
Invalid input stays 400: an empty project list, a project that no longer exists, or an invalid team name.
Config UI
Team: <name> (<slug>).Select at least one DevLake project.messageinline, which iserr.Error(): the full wrap chain in the errors library's debug format (Wraps: (2) …,Error types: (1) *hintdetail.withDetail …), plus stack frames and file paths whereverENABLE_STACKTRACEis on. The banner now readsPipeline failed. Hover over a failed task below to see the reason., and the failed-task tooltip shows the task'serrorName(the message chain only, for examplesubtask Collect Pull Requests ended unexpectedly caused by: graphql query got error) instead of itsmessage. The pipeline's ownerrorNamecan't be used for the banner because it embeds each failed task'sError()text. Nothing is lost for debugging: every message in the chain is still in the tooltip, and the fullmessageis unchanged in the API, the database and the pipeline logs.Test plan
causes, helper body data kept, 500 generic, malformed JSON and validation errors → 400), one for the Test Connection remap, and the fix(otel): remove project placements in the project deletion transaction #74 hook and OTel veto tests updated to the unwrapped veto and 409.devlakeandconfig-uilocally and ran every case through the API on the local stack:causes./rest/hint; unresolvable host → 502; unreachable host → 504 after 10 s; missing fields and malformed JSON → 400.causes.Wraps:/Error types:lines.Notes for reviewers
srvhelperand the GitHub/Jira plugins are unchanged. The failed-pipeline fix does touch three upstream Config UI files (pipeline/components/info.tsx,task.tsxandtypes/task.ts), a few lines each, instead of changing how the upstream runner storesmessage.