Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/shared/utils/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ export const env = createEnv({
.number()
.gt(0.0, "scaling factor must be greater than 0")
.default(1.0),
// Retry prepareUserOp errors instead of immediately failing the transaction
EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS: boolEnvSchema(false),
},
clientPrefix: "NEVER_USED",
client: {},
Expand Down Expand Up @@ -169,6 +171,8 @@ export const env = createEnv({
process.env.EXPERIMENTAL__MINE_WORKER_MAX_POLL_INTERVAL_SECONDS,
EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR:
process.env.EXPERIMENTAL__MINE_WORKER_POLL_INTERVAL_SCALING_FACTOR,
EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS:
process.env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS,
SEND_WEBHOOK_QUEUE_CONCURRENCY: process.env.SEND_WEBHOOK_QUEUE_CONCURRENCY,
},
onValidationError: (error: ZodError) => {
Expand Down
27 changes: 24 additions & 3 deletions src/worker/tasks/send-transaction-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,19 @@ const _sendUserOp = async (
});
} catch (error) {
const errorMessage = wrapError(error, "Bundler").message;
job.log(`Failed to populate transaction: ${errorMessage}`);

// If retry is enabled for prepareUserOp errors, throw to trigger job retry
if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw error;
}

// Otherwise, return errored transaction as before
Comment on lines +298 to +305
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Throw a wrapped Error and fix log message to match the step.

  • Log says “populate transaction” but this is the prepare step.
  • Throwing the raw error can be non-Error/lose context; wrap consistently.
-    job.log(`Failed to populate transaction: ${errorMessage}`);
+    job.log(`Failed to prepare userop: ${errorMessage}`);
     
-    // If retry is enabled for prepareUserOp errors, throw to trigger job retry
+    // If retry is enabled, throw to trigger job retry
     if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
-      throw error;
+      throw wrapError(error, "Bundler");
     }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/worker/tasks/send-transaction-worker.ts around lines 298 to 305, the log
and thrown value are incorrect: change the job.log message to refer to the
"prepare" step (e.g., "Failed to prepare transaction" or "Failed to prepare
userOp") instead of "populate transaction", and when retry is enabled wrap the
original error in an Error object before throwing — include a clear contextual
message and attach the original error (use Error cause if available or include
the original error.message/stack) so retries receive a proper Error instance
with preserved context.

const erroredTransaction: ErroredTransaction = {
...queuedTransaction,
status: "errored",
errorMessage,
};
job.log(`Failed to populate transaction: ${errorMessage}`);
return erroredTransaction;
}

Expand Down Expand Up @@ -356,12 +363,19 @@ const _sendUserOp = async (
const errorMessage = `${
wrapError(error, "Bundler").message
} Failed to sign prepared userop`;
job.log(`Failed to sign userop: ${errorMessage}`);

// If retry is enabled for prepareUserOp errors, throw to trigger job retry
if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw error;
}

Comment on lines +368 to +372
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Rethrow a wrapped Error for consistent typing and telemetry.

Mirror the RPC path and the prepare catch: wrap before throwing.

-    if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
-      throw error;
-    }
+    if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
+      throw wrapError(error, "Bundler");
+    }
📝 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 retry is enabled for prepareUserOp errors, throw to trigger job retry
if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw error;
}
// If retry is enabled for prepareUserOp errors, throw to trigger job retry
if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw wrapError(error, "Bundler");
}
🤖 Prompt for AI Agents
In src/worker/tasks/send-transaction-worker.ts around lines 368-372, instead of
rethrowing the raw caught error, wrap it in a new Error with a consistent
message (matching the RPC/prepare catch pattern) and include the original error
as the cause (or append its stack/message) before throwing; this preserves
consistent typing and telemetry while retaining original error details for
debugging.

// Otherwise, return errored transaction as before
const erroredTransaction: ErroredTransaction = {
...queuedTransaction,
status: "errored",
errorMessage,
};
job.log(`Failed to sign userop: ${errorMessage}`);
return erroredTransaction;
}

Expand All @@ -383,12 +397,19 @@ const _sendUserOp = async (
const errorMessage = `${
wrapError(error, "Bundler").message
} Failed to bundle userop`;
job.log(`Failed to bundle userop: ${errorMessage}`);

// If retry is enabled for prepareUserOp errors, throw to trigger job retry
if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw error;
}

Comment on lines +403 to +406
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Same here: wrap before rethrowing.

Aligns error shape and ensures BullMQ receives a proper Error instance.

-    if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
-      throw error;
-    }
+    if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
+      throw wrapError(error, "Bundler");
+    }
📝 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 (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw error;
}
if (env.EXPERIMENTAL__RETRY_PREPARE_USEROP_ERRORS) {
throw wrapError(error, "Bundler");
}
🤖 Prompt for AI Agents
In src/worker/tasks/send-transaction-worker.ts around lines 403 to 406, the code
rethrows a non-Error value directly which can break BullMQ error handling;
instead wrap the original thrown value in a proper Error instance before
rethrowing. Replace the direct throw error with throwing a new Error constructed
from the original (e.g., new Error(error instanceof Error ? error.message :
String(error))) and, if supported, attach the original as a cause or set
error.stack to preserve debugging info so BullMQ receives a proper Error object.

// Otherwise, return errored transaction as before
const erroredTransaction: ErroredTransaction = {
...queuedTransaction,
status: "errored",
errorMessage,
};
job.log(`Failed to bundle userop: ${errorMessage}`);
return erroredTransaction;
}

Expand Down
Loading