Skip to main content

Base Error

JobQueueError

Base error class for all job queue errors.
message
string
required
Error message
code
string
required
Error code identifier
name
string
required
Error class name (‘JobQueueError’)
stack
string
Stack trace
All other error classes extend from JobQueueError.
import { JobQueueError } from '@platformatic/job-queue'

try {
  await queue.enqueueAndWait(payload, { timeout: 5000 });
} catch (error) {
  if (error instanceof JobQueueError) {
    console.error(`Queue error [${error.code}]: ${error.message}`);
  }
}

Timeout Errors

TimeoutError

Thrown when enqueueAndWait() exceeds the specified timeout.
message
string
required
Error message including job ID and timeout duration
code
string
required
Error code: 'TIMEOUT'
jobId
string
required
ID of the job that timed out
name
string
required
Error class name: 'TimeoutError'
When thrown:
  • Job doesn’t complete within the specified timeout period in enqueueAndWait()
  • The job continues processing in the background after timeout
import { TimeoutError } from '@platformatic/job-queue'

try {
  const result = await queue.enqueueAndWait(
    { task: 'long-running-job' },
    { timeout: 5000 } // 5 seconds
  );
  console.log('Result:', result);
} catch (error) {
  if (error instanceof TimeoutError) {
    console.error(`Job ${error.jobId} timed out`);
    // Job is still running, you can check status later
    const status = await queue.getStatus(error.jobId);
    console.log('Current status:', status?.state);
  }
}

Retry Errors

MaxRetriesError

Thrown when a job fails permanently after exhausting all retry attempts.
message
string
required
Error message including job ID, attempts, and last error message
code
string
required
Error code: 'MAX_RETRIES'
jobId
string
required
ID of the failed job
attempts
number
required
Number of attempts made before permanent failure
lastError
Error
required
The original error from the final attempt
name
string
required
Error class name: 'MaxRetriesError'
When thrown:
  • Job handler throws an error on every retry attempt
  • Total attempts reach maxAttempts (configured in queue or per-job)
  • Thrown by enqueueAndWait() when job fails permanently
import { MaxRetriesError } from '@platformatic/job-queue'

try {
  const result = await queue.enqueueAndWait(
    { userId: 123, action: 'send-notification' },
    { maxAttempts: 3 }
  );
} catch (error) {
  if (error instanceof MaxRetriesError) {
    console.error(`Job ${error.jobId} failed after ${error.attempts} attempts`);
    console.error('Last error:', error.lastError.message);
    
    // Log to error tracking service
    await errorTracker.log({
      jobId: error.jobId,
      attempts: error.attempts,
      error: error.lastError
    });
  }
}

// Also emitted as 'failed' event
queue.on('failed', (id, error) => {
  console.error(`Job ${id} failed permanently:`, error);
});

Job State Errors

JobNotFoundError

Thrown when attempting to operate on a non-existent job.
message
string
required
Error message including job ID
code
string
required
Error code: 'JOB_NOT_FOUND'
jobId
string
required
ID of the job that was not found
name
string
required
Error class name: 'JobNotFoundError'
When thrown:
  • Calling getStatus() with an invalid or expired job ID
  • Job result/error expired due to TTL
  • Invalid job ID provided
import { JobNotFoundError } from '@platformatic/job-queue'

try {
  const status = await queue.getStatus('invalid-job-id');
} catch (error) {
  if (error instanceof JobNotFoundError) {
    console.error(`Job ${error.jobId} not found or expired`);
  }
}

JobCancelledError

Thrown when waiting for a job that was cancelled.
message
string
required
Error message including job ID
code
string
required
Error code: 'JOB_CANCELLED'
jobId
string
required
ID of the cancelled job
name
string
required
Error class name: 'JobCancelledError'
When thrown:
  • enqueueAndWait() is waiting for a job that gets cancelled
  • Job is cancelled while handler is checking status
import { JobCancelledError } from '@platformatic/job-queue'

// Start a long-running job
const waitPromise = queue.enqueueAndWait(
  { task: 'process-video' },
  { id: 'video-123', timeout: 60000 }
);

// Cancel it from another part of your code
setTimeout(() => {
  queue.cancel('video-123');
}, 5000);

try {
  await waitPromise;
} catch (error) {
  if (error instanceof JobCancelledError) {
    console.log(`Job ${error.jobId} was cancelled`);
  }
}

JobFailedError

Thrown when enqueueAndWait() encounters a job that failed.
message
string
required
Error message including job ID and original error message
code
string
required
Error code: 'JOB_FAILED'
jobId
string
required
ID of the failed job
originalError
string
required
Original error message from the job handler
name
string
required
Error class name: 'JobFailedError'
When thrown:
  • enqueueAndWait() waits for a job that fails permanently
  • Different from MaxRetriesError - this wraps the serialized error message
import { JobFailedError } from '@platformatic/job-queue'

try {
  const result = await queue.enqueueAndWait(
    { userId: 'invalid-id' },
    { timeout: 10000 }
  );
} catch (error) {
  if (error instanceof JobFailedError) {
    console.error(`Job ${error.jobId} failed`);
    console.error('Error from handler:', error.originalError);
  }
}

Storage Errors

StorageError

Thrown when a storage operation fails.
message
string
required
Error message describing the storage failure
code
string
required
Error code: 'STORAGE_ERROR'
cause
Error
The underlying error from the storage backend
name
string
required
Error class name: 'StorageError'
When thrown:
  • Redis connection failures
  • File system errors (FileStorage)
  • Network issues with storage backend
  • Storage backend crashes or becomes unavailable
import { StorageError } from '@platformatic/job-queue'
import { RedisStorage } from '@platformatic/job-queue'
import Redis from 'ioredis'

const redis = new Redis({
  host: 'localhost',
  port: 6379,
  retryStrategy: (times) => {
    if (times > 3) return null; // Stop retrying
    return Math.min(times * 100, 2000);
  }
});

const queue = new Queue({
  storage: new RedisStorage(redis)
});

try {
  await queue.enqueue({ task: 'process-data' });
} catch (error) {
  if (error instanceof StorageError) {
    console.error('Storage operation failed:', error.message);
    if (error.cause) {
      console.error('Underlying error:', error.cause.message);
    }
    
    // Attempt reconnection or fallback
    await handleStorageFailure(error);
  }
}

// Also emitted as 'error' event
queue.on('error', (error) => {
  if (error instanceof StorageError) {
    console.error('Queue storage error:', error);
  }
});

Error Handling Patterns

Comprehensive Error Handling

import {
  JobQueueError,
  TimeoutError,
  MaxRetriesError,
  JobCancelledError,
  JobFailedError,
  JobNotFoundError,
  StorageError
} from '@platformatic/job-queue'

async function processWithErrorHandling(payload: any) {
  try {
    const result = await queue.enqueueAndWait(
      payload,
      { 
        timeout: 30000,
        maxAttempts: 3
      }
    );
    return result;
  } catch (error) {
    if (error instanceof TimeoutError) {
      // Job timed out but may still complete
      console.warn(`Job ${error.jobId} timed out, checking status later`);
      scheduleStatusCheck(error.jobId);
      throw error;
    } 
    else if (error instanceof MaxRetriesError) {
      // Job failed permanently
      console.error(`Job failed after ${error.attempts} attempts`);
      await notifyAdmin(error);
      throw error;
    } 
    else if (error instanceof JobCancelledError) {
      // Job was cancelled
      console.log(`Job ${error.jobId} was cancelled`);
      return null;
    } 
    else if (error instanceof JobFailedError) {
      // Job failed with specific error
      console.error(`Job failed: ${error.originalError}`);
      throw error;
    } 
    else if (error instanceof StorageError) {
      // Storage backend issue
      console.error('Storage error:', error.cause);
      await alertOps(error);
      throw error;
    } 
    else if (error instanceof JobQueueError) {
      // Other queue errors
      console.error(`Queue error [${error.code}]: ${error.message}`);
      throw error;
    } 
    else {
      // Unexpected error
      console.error('Unexpected error:', error);
      throw error;
    }
  }
}

Retry with Backoff

async function enqueueWithRetry(payload: any, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await queue.enqueue(payload);
    } catch (error) {
      if (error instanceof StorageError && i < retries - 1) {
        // Wait with exponential backoff
        await new Promise(resolve => 
          setTimeout(resolve, Math.pow(2, i) * 1000)
        );
        continue;
      }
      throw error;
    }
  }
}

Graceful Degradation

async function enqueueOrFallback(payload: any) {
  try {
    await queue.enqueue(payload);
    return { status: 'queued' };
  } catch (error) {
    if (error instanceof StorageError) {
      // Fallback to synchronous processing
      console.warn('Queue unavailable, processing synchronously');
      const result = await processJobDirectly(payload);
      return { status: 'completed', result };
    }
    throw error;
  }
}