Skip to content

fix(msteams): use formatUnknownError instead of String(err) for error logging#59321

Merged
BradGroux merged 1 commit intoopenclaw:mainfrom
BradGroux:fix/msteams-error-stringification
Apr 2, 2026
Merged

fix(msteams): use formatUnknownError instead of String(err) for error logging#59321
BradGroux merged 1 commit intoopenclaw:mainfrom
BradGroux:fix/msteams-error-stringification

Conversation

@BradGroux
Copy link
Copy Markdown
Contributor

Replaces String(err) with the existing formatUnknownError() utility across the msteams extension. This prevents [object Object] appearing in error logs when non-Error objects are caught (e.g., Axios errors, Bot Framework SDK error objects).

The formatUnknownError() function already exists in extensions/msteams/src/errors.ts and properly handles Error instances, strings, nulls, and arbitrary objects.

Fixes #53910

@BradGroux BradGroux added the channel: msteams Channel integration: msteams label Apr 2, 2026
Copilot AI review requested due to automatic review settings April 2, 2026 01:22
@openclaw-barnacle openclaw-barnacle bot added size: XS maintainer Maintainer-authored PR labels Apr 2, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 2, 2026

Greptile Summary

This PR replaces String(err) with the existing formatUnknownError() utility across five files in the msteams extension, fixing the [object Object] log output that occurs when non-Error objects (e.g. plain-object throws) are caught. New imports are added to channel.ts, monitor-handler.ts, and onboarding.ts; monitor.ts and monitor-handler/message-handler.ts already had the import. The change is well-scoped and consistent.

  • All changed filesformatUnknownError returns err.message for Error instances, whereas String(err) called err.toString() which includes the error class prefix (e.g. "TypeError: ...", "Error: listen EADDRINUSE ..."). For most Node.js system errors the class name is embedded in the message itself, so real-world impact is low, but reviewers should be aware of the semantic shift.
  • monitor-handler/message-handler.ts line 551 — the context.sendActivity user-facing message previously used err instanceof Error ? err.message : String(err); the new formatUnknownError(err) will produce JSON.stringify(err) for non-Error thrown objects, potentially sending verbose JSON to end users in Teams. Since Axios and Bot Framework errors are Error subclasses this path is rarely hit in practice, but it is worth considering.

Confidence Score: 4/5

  • Safe to merge; the fix is correct and well-scoped with only minor semantic trade-offs to be aware of.
  • The change is a straightforward, consistent substitution of a well-tested utility function. All import additions are correct, the utility itself handles all edge cases, and the primary motivation (eliminating [object Object] in logs) is fully achieved. Two minor points prevent a perfect score: the loss of the error class name prefix for Error instances (cosmetic in most cases), and the theoretical exposure of verbose JSON in a user-facing Teams message for exotic non-Error thrown objects.
  • extensions/msteams/src/monitor-handler/message-handler.ts — the context.sendActivity call at line 551 is the one place where formatUnknownError output is shown directly to end users rather than written to logs.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/msteams/src/monitor-handler/message-handler.ts
Line: 551

Comment:
**User-facing message may expose verbose JSON for non-Error thrown objects**

The previous code used `err instanceof Error ? err.message : String(err)`, which for non-`Error` thrown objects (plain objects, Axios-like shapes) produced the unhelpful `[object Object]`. The new `formatUnknownError(err)` improves on that — but for non-`Error` objects it falls through to `JSON.stringify(err)`, which could produce a large JSON blob sent directly to end users in Teams.

For internal log calls (e.g. `log.error`, `runtime.error`) this is fine — full detail is desirable in logs. For the `context.sendActivity` user-facing message, you may want a tighter cap:

```suggestion
        await context.sendActivity(`⚠️ Agent failed: ${err instanceof Error ? err.message : formatUnknownError(err)}`);
```

This preserves the correct `err.message` path for `Error` instances (which covers Axios errors and Bot Framework SDK errors since they extend `Error`) while still using `formatUnknownError` as a fallback for exotic thrown values — limiting what a plain-object throw would surface to the user.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/msteams/src/monitor.ts
Line: 270-271

Comment:
**`formatUnknownError` drops the error class name for `Error` instances**

`formatUnknownError(err)` returns `err.message` for `Error` instances, while the previous `String(err)` called `err.toString()` which produces `"ErrorName: message"` (e.g. `"TypeError: ..."`, `"Error: listen EADDRINUSE :::3000"`).

For this `httpServer.on("error", ...)` callback and the `httpServer.close` callback below, the thrown values are always Node.js `Error` instances. The error _class_ name is often meaningful context in server-level errors (e.g. distinguishing `EADDRINUSE` from `ENOTFOUND` from a generic `Error`). Node.js system errors do typically include the code in `err.message` (e.g. `"listen EADDRINUSE :::`), so in practice the information is usually preserved — but it is worth being aware of this trade-off across all the changed call sites. No action is strictly required, just flagging the change in semantics.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(msteams): use formatUnknownError ins..." | Re-trigger Greptile

await context.sendActivity(
`⚠️ Agent failed: ${err instanceof Error ? err.message : String(err)}`,
);
await context.sendActivity(`⚠️ Agent failed: ${formatUnknownError(err)}`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 User-facing message may expose verbose JSON for non-Error thrown objects

The previous code used err instanceof Error ? err.message : String(err), which for non-Error thrown objects (plain objects, Axios-like shapes) produced the unhelpful [object Object]. The new formatUnknownError(err) improves on that — but for non-Error objects it falls through to JSON.stringify(err), which could produce a large JSON blob sent directly to end users in Teams.

For internal log calls (e.g. log.error, runtime.error) this is fine — full detail is desirable in logs. For the context.sendActivity user-facing message, you may want a tighter cap:

Suggested change
await context.sendActivity(`⚠️ Agent failed: ${formatUnknownError(err)}`);
await context.sendActivity(`⚠️ Agent failed: ${err instanceof Error ? err.message : formatUnknownError(err)}`);

This preserves the correct err.message path for Error instances (which covers Axios errors and Bot Framework SDK errors since they extend Error) while still using formatUnknownError as a fallback for exotic thrown values — limiting what a plain-object throw would surface to the user.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/monitor-handler/message-handler.ts
Line: 551

Comment:
**User-facing message may expose verbose JSON for non-Error thrown objects**

The previous code used `err instanceof Error ? err.message : String(err)`, which for non-`Error` thrown objects (plain objects, Axios-like shapes) produced the unhelpful `[object Object]`. The new `formatUnknownError(err)` improves on that — but for non-`Error` objects it falls through to `JSON.stringify(err)`, which could produce a large JSON blob sent directly to end users in Teams.

For internal log calls (e.g. `log.error`, `runtime.error`) this is fine — full detail is desirable in logs. For the `context.sendActivity` user-facing message, you may want a tighter cap:

```suggestion
        await context.sendActivity(`⚠️ Agent failed: ${err instanceof Error ? err.message : formatUnknownError(err)}`);
```

This preserves the correct `err.message` path for `Error` instances (which covers Axios errors and Bot Framework SDK errors since they extend `Error`) while still using `formatUnknownError` as a fallback for exotic thrown values — limiting what a plain-object throw would surface to the user.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 270 to 271

httpServer.on("error", (err) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 formatUnknownError drops the error class name for Error instances

formatUnknownError(err) returns err.message for Error instances, while the previous String(err) called err.toString() which produces "ErrorName: message" (e.g. "TypeError: ...", "Error: listen EADDRINUSE :::3000").

For this httpServer.on("error", ...) callback and the httpServer.close callback below, the thrown values are always Node.js Error instances. The error class name is often meaningful context in server-level errors (e.g. distinguishing EADDRINUSE from ENOTFOUND from a generic Error). Node.js system errors do typically include the code in err.message (e.g. "listen EADDRINUSE :::), so in practice the information is usually preserved — but it is worth being aware of this trade-off across all the changed call sites. No action is strictly required, just flagging the change in semantics.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/msteams/src/monitor.ts
Line: 270-271

Comment:
**`formatUnknownError` drops the error class name for `Error` instances**

`formatUnknownError(err)` returns `err.message` for `Error` instances, while the previous `String(err)` called `err.toString()` which produces `"ErrorName: message"` (e.g. `"TypeError: ..."`, `"Error: listen EADDRINUSE :::3000"`).

For this `httpServer.on("error", ...)` callback and the `httpServer.close` callback below, the thrown values are always Node.js `Error` instances. The error _class_ name is often meaningful context in server-level errors (e.g. distinguishing `EADDRINUSE` from `ENOTFOUND` from a generic `Error`). Node.js system errors do typically include the code in `err.message` (e.g. `"listen EADDRINUSE :::`), so in practice the information is usually preserved — but it is worth being aware of this trade-off across all the changed call sites. No action is strictly required, just flagging the change in semantics.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

Copilot AI left a 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 improves MS Teams extension error logging by replacing String(err) with the existing formatUnknownError() helper, preventing unhelpful [object Object] messages when non-Error values are thrown/caught.

Changes:

  • Use formatUnknownError() in onboarding flow error notes.
  • Use formatUnknownError() for provider/server and handler error logs in the monitor runtime.
  • Use formatUnknownError() in message dispatch/session-meta error paths and resolve flows.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
extensions/msteams/src/onboarding.ts Improves channel lookup failure messaging by formatting unknown error types.
extensions/msteams/src/monitor.ts Formats provider resolve/server lifecycle errors for more actionable logs.
extensions/msteams/src/monitor-handler/message-handler.ts Formats dispatch/session recording errors to avoid [object Object] in logs and user-facing failure messages.
extensions/msteams/src/monitor-handler.ts Formats handler + file upload failure errors consistently in logs and activity replies.
extensions/msteams/src/channel.ts Formats resolve failures when building directory/allowlist results.

Comment on lines +98 to +99
log.debug?.("file upload failed", { uploadId, error: formatUnknownError(err) });
await context.sendActivity(`File upload failed: ${formatUnknownError(err)}`);
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

formatUnknownError(err) is called twice here (structured log + user-facing message). Consider computing it once and reusing the value so the formatting is consistent and you avoid double JSON.stringify work for non-Error objects.

Suggested change
log.debug?.("file upload failed", { uploadId, error: formatUnknownError(err) });
await context.sendActivity(`File upload failed: ${formatUnknownError(err)}`);
const formattedError = formatUnknownError(err);
log.debug?.("file upload failed", { uploadId, error: formattedError });
await context.sendActivity(`File upload failed: ${formattedError}`);

Copilot uses AI. Check for mistakes.
Comment on lines +547 to +551
} catch (err) {
log.error("dispatch failed", { error: String(err) });
runtime.error?.(`msteams dispatch failed: ${String(err)}`);
log.error("dispatch failed", { error: formatUnknownError(err) });
runtime.error?.(`msteams dispatch failed: ${formatUnknownError(err)}`);
try {
await context.sendActivity(
`⚠️ Agent failed: ${err instanceof Error ? err.message : String(err)}`,
);
await context.sendActivity(`⚠️ Agent failed: ${formatUnknownError(err)}`);
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

formatUnknownError(err) is computed 3 times in this catch block (log, runtime error, and user-facing activity). Consider computing it once (e.g., const errMsg = formatUnknownError(err)) and reusing it to avoid repeated JSON.stringify work for non-Error objects and keep the output consistent across all three call sites.

Copilot uses AI. Check for mistakes.
@BradGroux BradGroux self-assigned this Apr 2, 2026
… logging

Replace String(err) with the existing formatUnknownError() utility across
the msteams extension to prevent [object Object] in error logs when
non-Error objects are thrown (e.g., Axios errors, Bot Framework SDK errors).

Fixes openclaw#53910
@BradGroux BradGroux force-pushed the fix/msteams-error-stringification branch from d2bd489 to 68e4ff1 Compare April 2, 2026 02:00
@BradGroux BradGroux merged commit 03c64df into openclaw:main Apr 2, 2026
42 checks passed
lawrence3699 added a commit to lawrence3699/openclaw that referenced this pull request Apr 2, 2026
Replace `String(err)` with `formatErrorMessage()` from plugin-sdk in
feishu monitor.account.ts. `String(err)` produces `[object Object]` for
non-Error thrown values (e.g., Lark SDK error objects), hiding the actual
error details. `formatErrorMessage()` traverses the `.cause` chain and
handles all error types properly.

This follows the same pattern applied to msteams in openclaw#59321.
ancientitguybot-dev pushed a commit to KaiWalter/openclaw that referenced this pull request Apr 3, 2026
… logging (openclaw#59321)

Replaces String(err) with the existing formatUnknownError() utility across
the msteams extension to prevent [object Object] appearing in error logs
when non-Error objects are caught (e.g., Axios errors, Bot Framework SDK
error objects).

Fixes openclaw#53910

thanks @BradGroux
steipete pushed a commit to duncanita/openclaw that referenced this pull request Apr 4, 2026
… logging (openclaw#59321)

Replaces String(err) with the existing formatUnknownError() utility across
the msteams extension to prevent [object Object] appearing in error logs
when non-Error objects are caught (e.g., Axios errors, Bot Framework SDK
error objects).

Fixes openclaw#53910

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

Labels

channel: msteams Channel integration: msteams maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: msteams typing/send errors logged as [object Object] — error not stringified

2 participants