fix/clone error#30
Conversation
There was a problem hiding this comment.
Pull Request Overview
Purpose: Address cloning failures for workflow activity arguments, improve error messaging, modernize lint configuration, and add test coverage for clone errors.
- Added defensive cloning with explicit DataCloneError handling and clearer error messages.
- Introduced new ESLint flat config and updated dev dependencies; removed legacy ESLint directives.
- Added a test validating failure when non‑cloneable arguments (functions) are passed; minor API/signature adjustments in triggers and tests.
Reviewed Changes
Copilot reviewed 19 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/workflows/index.ts | Removed obsolete ESLint disable comments; no logic change. |
| src/worker/Worker.ts | Minor optional chaining simplification for workflow args invocation. |
| src/worker/DefaultRetryPolicy.ts | Refactored constructor from parameter property to explicit assignment. |
| src/tests/workflows.test.ts | Removed unused test context parameter for cleanliness. |
| src/tests/workflow-throws.test.ts | Added test asserting clone error message behavior. |
| src/tests/workflow-store.test.ts | Removed unused test parameter t. |
| src/tests/workflow-functions.test.ts | Removed unused test parameters; minor arg mapping change. |
| src/tests/triggers/math.ts | Changed trigger start signature (removed run parameter). |
| src/tests/triggers.test.ts | Removed unused test parameter. |
| src/tests/store.test.ts | Removed unused test parameter. |
| src/tests/diagnostics/diagnostics.test.ts | Removed unused test parameters. |
| src/tests/activities/throw-message.ts | Removed ESLint directive; still throws string literal. |
| src/tests/activities/move.ts | Added conditional guard around y increment; no functional change given restricted direction type. |
| src/stores/DurableFunctionsWorkflowHistoryStore.ts | Removed ESLint directive comment only. |
| src/serialization/serialize-error.ts | Removed ESLint directive comments; logic unchanged. |
| src/proxy/proxyActivities.ts | Implemented try/catch around structuredClone with custom error message on DataCloneError. |
| package.json | Bumped version and updated dev dependencies (ESLint ecosystem). |
| eslint.config.js | Added new flat ESLint configuration. |
| .eslintrc.cjs | Removed legacy ESLint configuration file. |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| name: "math", | ||
| options: undefined, | ||
| start: (workflow: { name: string }, run) => { | ||
| start: (workflow: { name: string }) => { |
There was a problem hiding this comment.
The start function signature dropped the run parameter but workflow.start still calls trigger.start(workflow, run); this creates a type/interface mismatch and may fail TypeScript checks or mislead future usage. Restore the second parameter (even if unused) as start: (workflow: { name: string }, run: (id: string, payload: any) => Promise) => { ... } to align with the expected trigger interface.
| start: (workflow: { name: string }) => { | |
| start: (workflow: { name: string }, run: (id: string, payload: any) => Promise<any>) => { |
| @@ -1,4 +1,3 @@ | |||
| export async function throwMessage(message: string): Promise<void> { | |||
| // eslint-disable-next-line @typescript-eslint/no-throw-literal | |||
| throw message; | |||
There was a problem hiding this comment.
Throwing a string literal loses stack enrichment and makes downstream error handling (instanceof Error, error.cause, etc.) unreliable. Replace with throw new Error(message) to preserve standard error semantics.
| throw message; | |
| throw new Error(message); |
| let originalArgs = new Array<any>(); | ||
| try { | ||
| originalArgs = structuredClone(args); | ||
| } catch (e) { | ||
| if (e && typeof e === "object" && | ||
| "name" in e && e.name === "DataCloneError" && | ||
| "message" in e) { | ||
| throw new Error(`simple-workflows: Failed to clone argument for workflow '${workflowId}/${activityName}' - all arguments must be cloneable (${e.message})`); | ||
| } | ||
| throw e; | ||
| } |
There was a problem hiding this comment.
[nitpick] originalArgs can be declared more simply (const cloned = structuredClone(args)) and only after the try succeeds—initializing with new Array() adds noise. Suggest: let originalArgs; try { originalArgs = structuredClone(args); } catch (...) { ... } or const originalArgs = structuredClone(args); to reduce redundancy.
| if (e && typeof e === "object" && | ||
| "name" in e && e.name === "DataCloneError" && | ||
| "message" in e) { | ||
| throw new Error(`simple-workflows: Failed to clone argument for workflow '${workflowId}/${activityName}' - all arguments must be cloneable (${e.message})`); |
There was a problem hiding this comment.
Re-throwing with a new Error for DataCloneError discards the original stack and cause. Use the error cause option: throw new Error(simple-workflows: Failed to clone argument for workflow '${workflowId}/${activityName}' - all arguments must be cloneable (${(e as Error).message}), { cause: e }); to retain diagnostic context.
| throw new Error(`simple-workflows: Failed to clone argument for workflow '${workflowId}/${activityName}' - all arguments must be cloneable (${e.message})`); | |
| throw new Error(`simple-workflows: Failed to clone argument for workflow '${workflowId}/${activityName}' - all arguments must be cloneable (${e.message})`, { cause: e }); |
No description provided.