Skip to main content
The WaitingError is a special error class used to signal that a job has been manually moved back to the waiting state during processing. This error prevents the worker from trying to complete or fail the job.

Class Definition

class WaitingError extends Error {
  constructor(message?: string)
}

Usage

When you manually move a job to wait using job.moveToWait(), you must throw WaitingError to signal to the worker that the job has been intentionally moved and should not be marked as completed or failed.
import { Worker, WaitingError } from 'bullmq';

const worker = new Worker(
  'queueName',
  async (job: Job, token?: string) => {
    try {
      await doSomething();
    } catch (error) {
      // Move job back to wait for retry
      await job.moveToWait(token);
      
      // Must throw WaitingError to signal the worker
      throw new WaitingError();
    }
  },
  { connection },
);

When to Use

Manual Retry

Retry a job immediately without incrementing attempts counter

Rate Limiting

Move job back to wait when hitting external rate limits

Resource Contention

Retry when a required resource is temporarily unavailable

Conditional Processing

Re-queue job based on dynamic conditions

Important Notes

Always throw WaitingError after calling job.moveToWait(). If you don’t throw this error, the worker will try to complete the job, causing conflicts.
WaitingError does not increment the attemptsMade counter, but it does increment attemptsStarted. This is useful for implementing custom retry logic without exhausting the configured retry attempts.

Example with Rate Limiting

import { Worker, WaitingError } from 'bullmq';

const worker = new Worker(
  'api-calls',
  async (job: Job, token?: string) => {
    try {
      const response = await callExternalAPI(job.data);
      return response;
    } catch (error) {
      if (error.response?.status === 429) {
        // Rate limited - move back to wait
        const retryAfter = error.response.headers['retry-after'];
        await queue.rateLimit(retryAfter * 1000);
        await job.moveToWait(token);
        
        // Signal that job was moved to wait
        throw new WaitingError();
      }
      
      // Other errors trigger normal retry logic
      throw error;
    }
  },
  { connection },
);

Comparison with Other Errors

Error TypeJob StateAttempts CounterUse Case
WaitingErrorwaitNot incrementedManual retry
DelayedErrordelayedNot incrementedManual delay
RateLimitErrorwaitNot incrementedRate limiting
WaitingChildrenErrorwaiting-childrenNot incrementedParent-child dependencies
Regular Errorfailed → waitIncrementedStandard retry

Manual Retrying Pattern

Learn about manual retry strategies

Job.moveToWait API

API reference for moveToWait method

Rate Limiting

Implement rate limiting strategies

Process Step Jobs

Multi-step job processing patterns

Build docs developers (and LLMs) love