Skip to content

fix: improve error logging to serialize Response objects#1115

Open
igoramf wants to merge 1 commit intomainfrom
fix/log-undefined-response
Open

fix: improve error logging to serialize Response objects#1115
igoramf wants to merge 1 commit intomainfrom
fix/log-undefined-response

Conversation

@igoramf
Copy link
Contributor

@igoramf igoramf commented Mar 10, 2026

Summary

  • Fixed console.error(init?.body, response) in clients/withManifest.ts and console.error(input, response) in utils/fetchAPI.ts which logged (undefined) [object Response] in observability tools (HyperDX)
  • Now logs HTTP status, URL and response body for actionable debugging: Invoke error 500 Internal Server Error - /live/invoke/... {"message":"..."}

Test plan

  • Tested locally with mock fetch — original produces undefined [object Response], fix produces Invoke error 500 Internal Server Error - /live/invoke/... {body}

Summary by cubic

Improves error logging by serializing fetch Response objects. Logs status, URL, and body for clearer debugging in tools like HyperDX.

  • Bug Fixes
    • Replace raw console.error(..., response) with formatted messages in clients/withManifest.ts and utils/fetchAPI.ts.
    • Log HTTP status, status text, request URL/input, and response body.
    • Preserve x-correlation-id and pass it to InvokeError.

Written for commit e0e9a41. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling and logging to provide more detailed information when API requests encounter issues, including status codes and response details for better troubleshooting and error tracking.

console.error was logging raw Response objects, producing
"(undefined) [object Response]" in observability tools like HyperDX.
Now logs status, URL and response body for actionable debugging.
@github-actions
Copy link
Contributor

Tagging Options

Should a new tag be published when this PR is merged?

  • 👍 for Patch 1.177.6 update
  • 🎉 for Minor 1.178.0 update
  • 🚀 for Major 2.0.0 update

Copy link

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

Choose a reason for hiding this comment

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

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="utils/fetchAPI.ts">

<violation number="1" location="utils/fetchAPI.ts:19">
P2: Log the request URL explicitly for `Request` inputs; interpolating `input` directly still serializes as `[object Request]`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

console.error(input, response);
const errorBody = await response.text();
console.error(
`fetchAPI error ${response.status} ${response.statusText} - ${input}`,
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 10, 2026

Choose a reason for hiding this comment

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

P2: Log the request URL explicitly for Request inputs; interpolating input directly still serializes as [object Request].

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At utils/fetchAPI.ts, line 19:

<comment>Log the request URL explicitly for `Request` inputs; interpolating `input` directly still serializes as `[object Request]`.</comment>

<file context>
@@ -14,6 +14,10 @@ export const fetchAPI = async <T>(
-  console.error(input, response);
+  const errorBody = await response.text();
+  console.error(
+    `fetchAPI error ${response.status} ${response.statusText} - ${input}`,
+    errorBody,
+  );
</file context>
Suggested change
`fetchAPI error ${response.status} ${response.statusText} - ${input}`,
`fetchAPI error ${response.status} ${response.statusText} - ${typeof input === "string" ? input : input.url}`,
Fix with Cubic

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

The PR enhances error handling and logging in two API utility files. withManifest.ts now extracts correlation IDs from response headers and parses JSON error bodies when available, while fetchAPI.ts improves error logging by including the response text body and formatted status information.

Changes

Cohort / File(s) Summary
Error Handling & Logging Improvements
clients/withManifest.ts, utils/fetchAPI.ts
Enhanced error responses to extract and log detailed diagnostic information: correlation ID header extraction, JSON error body parsing, and improved error message formatting with status codes and response text.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • mcandeia

Poem

🐰 When errors hop along the wire,
We catch them with more detail's fire!
Headers and bodies, now we see,
What went wrong in clarity—
Debugging's easier, hoorah! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: improve error logging to serialize Response objects' directly aligns with the main objective to fix error logging by serializing Response objects instead of logging raw objects that produce '(undefined) [object Response]' in observability tools.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/log-undefined-response

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
utils/fetchAPI.ts (1)

17-20: Normalize Request inputs before logging.

fetchAPI accepts Request, but ${input} still logs as [object Request]. That keeps this path opaque in observability even after fixing the Response case. Use input.url (and ideally input.method) when input is a Request.

Proposed change
   const errorBody = await response.text();
+  const requestLabel = typeof input === "string"
+    ? input
+    : `${input.method} ${input.url}`;
   console.error(
-    `fetchAPI error ${response.status} ${response.statusText} - ${input}`,
+    `fetchAPI error ${response.status} ${response.statusText} - ${requestLabel}`,
     errorBody,
   );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@utils/fetchAPI.ts` around lines 17 - 20, The fetchAPI error logging currently
prints Request objects as "[object Request]" making failures opaque; in the
fetchAPI function, detect when the input is a Request (e.g., using input
instanceof Request or checking for input.url) and log input.url and input.method
instead of interpolating the whole object; for non-Request inputs fall back to
the existing string/URL logging (or input.toString()) so the console.error line
uses either `${input.url} ${input.method}` when a Request or the original input
value otherwise, and keep the rest of the errorBody/response.status/statusText
logging unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@clients/withManifest.ts`:
- Around line 167-172: The content-type check and JSON parsing need to be made
robust: change the header check to detect JSON media types with parameters
(e.g., use response.headers.get("content-type")?.includes("application/json") or
startsWith) and wrap JSON.parse(errorBody) in a try/catch; if parse succeeds use
the parsed object as the InvokeError cause, otherwise fall back to using the raw
errorBody (or undefined) as the cause so you still throw the normalized
InvokeError with the correlationId. Ensure you update the branch around
response, errorBody, InvokeError, and correlationId to always throw an
InvokeError (with correlationId) even when JSON parsing fails.

---

Nitpick comments:
In `@utils/fetchAPI.ts`:
- Around line 17-20: The fetchAPI error logging currently prints Request objects
as "[object Request]" making failures opaque; in the fetchAPI function, detect
when the input is a Request (e.g., using input instanceof Request or checking
for input.url) and log input.url and input.method instead of interpolating the
whole object; for non-Request inputs fall back to the existing string/URL
logging (or input.toString()) so the console.error line uses either
`${input.url} ${input.method}` when a Request or the original input value
otherwise, and keep the rest of the errorBody/response.status/statusText logging
unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dce82650-bcbe-47fb-b998-d2b8e724700e

📥 Commits

Reviewing files that changed from the base of the PR and between 0c589c0 and e0e9a41.

📒 Files selected for processing (2)
  • clients/withManifest.ts
  • utils/fetchAPI.ts

Comment on lines 167 to 172
if (response.headers.get("content-type") === "application/json") {
const errorObj = JSON.parse(error);
const errorObj = JSON.parse(errorBody);
throw new InvokeError(`${response.status}: ${response.statusText}`, {
cause: errorObj,
correlationId: response.headers.get("x-correlation-id"),
correlationId,
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate the file and examine the specific lines mentioned
git ls-files | grep -E "withManifest\.(ts|js)$"

Repository: deco-cx/deco

Length of output: 79


🏁 Script executed:

# Read the file around the specified lines
wc -l clients/withManifest.ts

Repository: deco-cx/deco

Length of output: 83


🏁 Script executed:

# Get context around lines 167-172
sed -n '155,180p' clients/withManifest.ts

Repository: deco-cx/deco

Length of output: 815


🏁 Script executed:

# Search for other JSON.parse calls in the codebase to see error handling patterns
rg 'JSON\.parse' -B 2 -A 2 --type ts --type js

Repository: deco-cx/deco

Length of output: 13161


🏁 Script executed:

# Check the InvokeError definition and how correlationId is used
rg 'class InvokeError|interface InvokeError' -A 10 --type ts

Repository: deco-cx/deco

Length of output: 627


🏁 Script executed:

# Check if there's any error handling around JSON parsing elsewhere
rg 'try.*JSON\.parse|JSON\.parse.*catch' --type ts --type js

Repository: deco-cx/deco

Length of output: 774


Guard JSON error parsing and accept charset-suffixed JSON.

The current branch only matches an exact application/json header, which misses common variants like application/json; charset=utf-8. Additionally, JSON.parse(errorBody) has no guard, so malformed or empty JSON bodies throw a raw SyntaxError, causing callers to lose the normalized InvokeError path and its correlationId for observability.

Proposed fix
+  const contentType = response.headers.get("content-type") ?? "";
-  if (response.headers.get("content-type") === "application/json") {
-    const errorObj = JSON.parse(errorBody);
+  if (contentType.startsWith("application/json")) {
+    let errorObj: unknown = errorBody;
+    try {
+      errorObj = errorBody ? JSON.parse(errorBody) : null;
+    } catch {
+      // Fall back to the raw body and preserve correlationId on InvokeError.
+    }
     throw new InvokeError(`${response.status}: ${response.statusText}`, {
       cause: errorObj,
       correlationId,
     });
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (response.headers.get("content-type") === "application/json") {
const errorObj = JSON.parse(error);
const errorObj = JSON.parse(errorBody);
throw new InvokeError(`${response.status}: ${response.statusText}`, {
cause: errorObj,
correlationId: response.headers.get("x-correlation-id"),
correlationId,
});
const contentType = response.headers.get("content-type") ?? "";
if (contentType.startsWith("application/json")) {
let errorObj: unknown = errorBody;
try {
errorObj = errorBody ? JSON.parse(errorBody) : null;
} catch {
// Fall back to the raw body and preserve correlationId on InvokeError.
}
throw new InvokeError(`${response.status}: ${response.statusText}`, {
cause: errorObj,
correlationId,
});
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@clients/withManifest.ts` around lines 167 - 172, The content-type check and
JSON parsing need to be made robust: change the header check to detect JSON
media types with parameters (e.g., use
response.headers.get("content-type")?.includes("application/json") or
startsWith) and wrap JSON.parse(errorBody) in a try/catch; if parse succeeds use
the parsed object as the InvokeError cause, otherwise fall back to using the raw
errorBody (or undefined) as the cause so you still throw the normalized
InvokeError with the correlationId. Ensure you update the branch around
response, errorBody, InvokeError, and correlationId to always throw an
InvokeError (with correlationId) even when JSON parsing fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant