Skip to content

fix: safely handle non-Error thrown values in StoreBackend#418

Open
chaoliang yan (lawrence3699) wants to merge 1 commit intolangchain-ai:mainfrom
lawrence3699:fix/safe-error-handling-in-store-backend
Open

fix: safely handle non-Error thrown values in StoreBackend#418
chaoliang yan (lawrence3699) wants to merge 1 commit intolangchain-ai:mainfrom
lawrence3699:fix/safe-error-handling-in-store-backend

Conversation

@lawrence3699
Copy link
Copy Markdown

Summary

  • Replace catch (e: any) with catch (e: unknown) in two StoreBackend methods (readFileContent, editFileContent)
  • Guard .message access with e instanceof Error check, falling back to String(e) for non-Error thrown values
  • Prevents error responses containing undefined when a non-Error value (string, number, object) is thrown

Test plan

  • Verify existing unit tests for StoreBackend.readFileContent and editFileContent still pass
  • Confirm error message is correctly captured when a non-Error value is thrown

Replace `catch (e: any) { e.message }` with `catch (e: unknown)` and
an `instanceof Error` check. If the caught value is not an Error
instance (e.g., a thrown string or object), accessing `.message`
returns `undefined`, producing unhelpful error messages like
"Error: undefined". The fix safely stringifies any thrown value.
Copilot AI review requested due to automatic review settings April 2, 2026 04:40
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 2, 2026

⚠️ No Changeset found

Latest commit: fd52341

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Copy Markdown

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 hardens StoreBackend error handling so that thrown non-Error values (e.g., strings) don’t lead to undefined error messages or unsafe property access, improving the reliability of backend error responses.

Changes:

  • Replaces catch (e: any) with catch (e: unknown) in StoreBackend.read() and StoreBackend.edit().
  • Guards .message access with e instanceof Error, falling back to String(e).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +361 to +362
} catch (e: unknown) {
return { error: e instanceof Error ? e.message : String(e) };
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.

For non-Error thrown values, String(e) will produce unhelpful output for objects (e.g., throw { foo: 1 } becomes "[object Object]"). If the intent is to preserve a meaningful message for thrown objects, consider handling common "error-like" shapes (e.g., object with a string message property) and/or providing a clearer fallback for null/undefined (e.g., "Unknown error").

Copilot uses AI. Check for mistakes.
} catch (e: any) {
return { error: e.message };
} catch (e: unknown) {
return { error: e instanceof Error ? e.message : String(e) };
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.

The new catch-handling behavior isn’t covered by existing unit tests. Consider adding tests that simulate read() failing with non-Error thrown values (e.g., a thrown string/number/object) to verify the returned error string is stable and not undefined.

Suggested change
return { error: e instanceof Error ? e.message : String(e) };
let message: string | undefined;
if (e instanceof Error) {
message = e.message;
} else if (typeof e === "string") {
message = e;
} else if (
e !== null &&
typeof e === "object" &&
"message" in e &&
typeof (e as { message?: unknown }).message === "string"
) {
message = (e as { message: string }).message;
} else if (
typeof e === "number" ||
typeof e === "boolean" ||
typeof e === "bigint" ||
typeof e === "symbol"
) {
message = String(e);
}
return {
error: message && message.length > 0
? message
: "Unknown error while reading file",
};

Copilot uses AI. Check for mistakes.
Comment on lines 449 to +454
const storeValue = this.convertFileDataToStoreValue(newFileData);
await store.put(namespace, filePath, storeValue);
return { path: filePath, filesUpdate: null, occurrences: occurrences };
} catch (e: any) {
return { error: `Error: ${e.message}` };
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
return { error: `Error: ${msg}` };
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.

PR description/test plan mention readFileContent / editFileContent, but the changes are in read() and edit(). Please update the PR description (and any related docs) so reviewers and future readers can match the change to the correct methods.

Copilot uses AI. Check for mistakes.
} catch (e: any) {
return { error: `Error: ${e.message}` };
} catch (e: unknown) {
const msg = e instanceof Error ? e.message : String(e);
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.

Same as above: String(e) will render thrown objects as "[object Object]" and may also produce "undefined"/"null" strings. If you want actionable error text for non-Error throws, consider extracting a string message property when present and using a friendlier fallback for nullish values.

Suggested change
const msg = e instanceof Error ? e.message : String(e);
const msg =
e instanceof Error
? e.message
: typeof e === "string"
? e
: e && typeof (e as any).message === "string"
? (e as any).message
: "Unknown error";

Copilot uses AI. Check for mistakes.
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.

2 participants