-
Notifications
You must be signed in to change notification settings - Fork 0
feat: include cause and context in API error messages #283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Enhanced handleRequestError() to surface actionable diagnostic info: - Extract and include 'cause' field (truncated to 200 chars) - Include summary of 'context' object (first 3 keys, values truncated) Error messages now show: HTTP 400: DAML_FAILURE - message (cause: actual_cause) [context: key1=val1] This helps debug DAML_FAILURE errors without needing to access logs.
|
Claude finished @HardlyDifficult's task —— View job PR Review: Enhanced Error DiagnosticsTodo List:
Review SummaryThis PR enhances error diagnostics by extracting and including ✅ Strengths
|
|
@cursor respond to feedback on this pr. improve where you can. |
|
I've addressed all the feedback from the PR review. Here's a summary of the improvements made: Code Changes in
Test Coverage Added:
All 326 unit tests pass, and lint/build checks are clean. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances the error handling in HttpClient.handleRequestError() to extract and display diagnostic information from DAML/Canton API error responses. It adds the cause field (truncated to 200 characters) and a summary of the context object (first 3 keys with values truncated to 50 characters) to error messages.
Changes:
- Enhanced error message formatting to include
causeandcontextfields from API error responses - Added truncation logic to keep error messages readable while preserving key diagnostic information
- Error messages now follow the format:
HTTP 400: DAML_FAILURE - message (cause: actual_cause) [context: key1=val1, key2=val2]
| const cause = typeof data['cause'] === 'string' ? data['cause'] : undefined; | ||
| const context = typeof data['context'] === 'object' && data['context'] !== null ? data['context'] : undefined; | ||
|
|
||
| // Build error message with all available details | ||
| let msg = `HTTP ${status}`; | ||
| if (code) { | ||
| msg += `: ${code}`; | ||
| } | ||
| if (message) { | ||
| msg += ` - ${message}`; | ||
| } | ||
| // Include cause for DAML/Canton errors - this is the actionable info | ||
| if (cause) { | ||
| // Truncate long causes but preserve the first ~200 chars which usually have the key info | ||
| const truncatedCause = cause.length > 200 ? `${cause.substring(0, 200)}...` : cause; | ||
| msg += ` (cause: ${truncatedCause})`; | ||
| } | ||
| // Include context summary if available | ||
| if (context) { | ||
| const contextObj = context as Record<string, unknown>; | ||
| const contextKeys = Object.keys(contextObj); | ||
| if (contextKeys.length > 0) { | ||
| // Show key context fields that help identify the failure location | ||
| const contextSummary = contextKeys | ||
| .slice(0, 3) | ||
| .map((k) => { | ||
| const v = contextObj[k]; | ||
| let vStr: string; | ||
| if (typeof v === 'string') { | ||
| vStr = v; | ||
| } else if (v === undefined) { | ||
| vStr = 'undefined'; | ||
| } else { | ||
| vStr = JSON.stringify(v); | ||
| } | ||
| return `${k}=${vStr.substring(0, 50)}`; | ||
| }) | ||
| .join(', '); | ||
| msg += ` [context: ${contextSummary}]`; | ||
| } | ||
| } |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new error message formatting logic that extracts and includes 'cause' and 'context' fields lacks test coverage. Consider adding unit tests to verify that cause and context are correctly extracted, truncated, and formatted in the error message. This is especially important for edge cases like long causes, contexts with many keys, contexts with circular references, and contexts that are arrays.
src/core/http/HttpClient.ts
Outdated
| } else if (v === undefined) { | ||
| vStr = 'undefined'; | ||
| } else { | ||
| vStr = JSON.stringify(v); |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSON.stringify can throw an error if the value contains circular references or cannot be serialized. Wrap this in a try-catch block and provide a fallback such as '[object]' or use a safe stringification approach.
src/core/http/HttpClient.ts
Outdated
| const code = typeof data['code'] === 'string' ? data['code'] : undefined; | ||
| const message = typeof data['message'] === 'string' ? data['message'] : undefined; | ||
| const cause = typeof data['cause'] === 'string' ? data['cause'] : undefined; | ||
| const context = typeof data['context'] === 'object' && data['context'] !== null ? data['context'] : undefined; |
Copilot
AI
Feb 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check typeof data['context'] === 'object' && data['context'] !== null will also match arrays. If the context field is an array instead of an object, casting it to Record<string, unknown> on line 207 would be semantically incorrect. Consider adding && !Array.isArray(data['context']) to the condition on line 189 to ensure context is specifically an object and not an array.
- Add Array.isArray check to prevent arrays from being processed as context - Add explicit null handling in context value serialization - Add try/catch for JSON.stringify to handle circular references and BigInt - Extract truncation limits as named constants (CAUSE_TRUNCATE_LENGTH, etc.) - Refactor context formatting into separate methods for better testability - Add comprehensive unit tests for cause/context extraction Co-authored-by: hardlydiff <hardlydiff@gmail.com>
Co-authored-by: hardlydiff <hardlydiff@gmail.com>
|
Claude finished @HardlyDifficult's task —— View job ✅ Excellent Implementation - All Key Issues Addressed!Todo List:
Review SummaryThis PR has been significantly improved and addresses all the major concerns from the previous review. The implementation now follows excellent defensive programming practices with comprehensive error handling and extensive test coverage. 🎉 Improvements Successfully Implemented1. Enhanced Type Safety (
|
|
Claude finished @HardlyDifficult's task —— View job Comprehensive PR Review: Enhanced Error Diagnostics ✅ Todo List:
🎉 Excellent Implementation!This PR represents a significant improvement to error diagnostics for DAML/Canton API interactions. The implementation effectively addresses all previous review feedback and demonstrates strong engineering practices. ✅ Key Strengths1. Robust Error Handling (
|
Fix inconsistent truncation behavior where context values were truncated without any indicator while cause values had an ellipsis appended. Now both truncation cases consistently show '...' when values exceed their respective length limits.
|
Claude finished @HardlyDifficult's task —— View job PR Review: Enhanced Error Diagnostics ✅Todo List:
🎉 Outstanding Implementation!This PR represents excellent engineering work that significantly enhances error diagnostics for DAML/Canton API interactions. The implementation demonstrates thoughtful design, robust error handling, and comprehensive testing. ✅ Strengths & Quality Assessment1. Robust Type Safety (
|
| Criteria | Rating | Notes |
|---|---|---|
| Code Quality | ⭐⭐⭐⭐⭐ | Excellent organization, defensive programming |
| Test Coverage | ⭐⭐⭐⭐⭐ | Comprehensive edge case coverage |
| Error Handling | ⭐⭐⭐⭐⭐ | Bulletproof with graceful degradation |
| Performance | ⭐⭐⭐⭐⭐ | Minimal overhead, bounded operations |
| Security | ⭐⭐⭐⭐⭐ | Safe handling of untrusted input |
| Maintainability | ⭐⭐⭐⭐⭐ | Clear structure, good documentation |
🚀 Recommendation
✅ APPROVE - Ready for Production
This implementation demonstrates exceptional attention to detail and follows all TypeScript/Node.js best practices. The enhanced error messages will provide significant value for developers debugging DAML/Canton API issues.
Key Benefits:
- Dramatically improved debugging experience for DAML/Canton errors
- Bulletproof error handling with comprehensive edge case coverage
- Clean, maintainable code following established patterns
- Production-ready with excellent test coverage
|
Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is ON. A Cloud Agent has been kicked off to fix the reported issue.
JSON.stringify can return undefined (not throw) for functions, Symbols, or objects with a toJSON() method that returns undefined. This could cause a TypeError when accessing .length on the result in formatContextSummary. Added nullish coalescing to ensure stringifyContextValue always returns a string.
|
Claude finished @HardlyDifficult's task —— View job Claude finished the PR review Todo List:
🎉 Excellent Implementation - All Major Concerns Addressed!Code Quality Assessment✅ Strengths1. Robust Type Safety ( const context =
typeof data['context'] === 'object' && data['context'] !== null && !Array.isArray(data['context'])
? data['context']
: undefined;✅ Perfect! Properly excludes arrays, null values, and ensures only plain objects are processed. 2. Safe Value Serialization ( try {
// JSON.stringify can return undefined for functions, Symbols, or objects with toJSON() returning undefined
return JSON.stringify(v) ?? '[Object]';
} catch {
// Handle circular references, BigInt, or other non-serializable values
return '[Object]';
}✅ Excellent defensive programming! Handles both exceptions and undefined returns from 3. Clean Code Organization
4. Consistent Error Message Format ( ✅ Previous Review Issues - All Successfully Addressed
Test Coverage Analysis🧪 Comprehensive Test Suite (13 targeted tests)Cause Extraction Tests (
Context Extraction Tests (
Integration Tests (
Security & Performance Assessment🔒 Security Analysis
⚡ Performance Analysis
Technical Excellence HighlightsError Resilience// Handles ALL possible JSON.stringify edge cases
try {
return JSON.stringify(v) ?? '[Object]';
} catch {
return '[Object]';
}Type Safety// Comprehensive type guarding prevents runtime errors
typeof data['context'] === 'object' &&
data['context'] !== null &&
!Array.isArray(data['context'])Final Assessment
🚀 Recommendation: ✅ APPROVEThis implementation demonstrates exceptional engineering quality and attention to detail. The enhanced error messages will significantly improve debugging experience for DAML/Canton API interactions while maintaining excellent safety standards. Key Benefits:
|
|
Bugbot Autofix prepared fixes for 1 of the 1 bugs found in the latest run.
|


Summary
handleRequestError()to surface actionable diagnostic info from DAML/Canton error responsescausefield (truncated to 200 chars)contextobject (first 3 keys, values truncated to 50 chars)Error messages now show:
Test plan
Note
Low Risk
Low risk: changes are confined to error-message formatting in
HttpClientplus tests, with no behavior changes to request execution beyond improved diagnostics.Overview
HttpClient.handleRequestError()now extractscause(string-only, truncated to 200 chars) and a summarizedcontextobject (plain-object only, first 3 keys, values truncated to 50 chars) from Axios error responses and appends them to the thrownApiErrormessage.Adds helper formatting/serialization utilities to safely stringify context values (including null/undefined and non-serializable/circular objects) and introduces extensive Jest coverage for cause/context inclusion, truncation, and invalid shapes (non-string cause, array/empty context).
Written by Cursor Bugbot for commit 4da9f1d. This will update automatically on new commits. Configure here.