thedotmack/claude-mem · error · Error

cannot process observation generation job after…

Error message

cannot process observation generation job after max_attempts is reached

What it means

When transitioning a job to 'processing', assertValidJobStatusTransition rejects the change if current.attempts >= current.maxAttempts. This caps how many times a job may be picked up for processing, preventing infinite processing loops on a permanently failing job.

Solutions

  1. Let the job fail permanently (transition to a failed/terminal status) instead of processing again
  2. Increase maxAttempts when creating the job if more retries are legitimately needed
  3. Inspect why each attempt failed before re-queuing; fix the underlying generation error first
  4. Guard worker claim logic: only transition to processing if attempts < maxAttempts

Example fix

// before
if (job.status === 'queued') await jobs.transitionStatus(job.id, 'processing');
// after
if (job.status === 'queued' && job.attempts < job.maxAttempts) {
  await jobs.transitionStatus(job.id, 'processing');
} else {
  await jobs.transitionStatus(job.id, 'failed');
}
Defensive patterns

Strategy: validation

Validate before calling

if (nextStatus === 'processing' && job.attempts >= job.maxAttempts) {
  throw new Error('attempts exhausted');
}

Try / catch

try {
  await jobs.transitionStatus(jobId, 'processing');
} catch (err) {
  if (err instanceof Error && err.message.includes('max_attempts is reached')) {
    await jobs.transitionStatus(jobId, 'failed');
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: transitionStatus(jobId, 'processing') on a job whose attempts counter has reached maxAttempts — e.g. a worker claiming a job again after maxAttempts failed attempts, or a buggy claim loop not incrementing checks.

Common situations: Cron/poll worker repeatedly retrying a poison job; queue re-delivery after visibility timeout when attempts were already exhausted; maxAttempts configured lower than the number of workers' retry rounds.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/7a41a199162fb032. Report an issue: GitHub.

Appendix: source

Thrown at src/storage/postgres/generation-jobs.ts:420

  completed: [],
  failed: [],
  cancelled: []
};

function assertValidJobStatusTransition(
  current: PostgresObservationGenerationJob,
  nextStatus: ObservationGenerationJobStatus
): void {
  if (TERMINAL_JOB_STATUSES.has(current.status)) {
    throw new Error(`cannot transition observation generation job from terminal status ${current.status}`);
  }

  if (!ALLOWED_JOB_TRANSITIONS[current.status].includes(nextStatus)) {
    throw new Error(`illegal observation generation job transition from ${current.status} to ${nextStatus}`);
  }

  if (nextStatus === 'processing' && current.attempts >= current.maxAttempts) {
    throw new Error('cannot process observation generation job after max_attempts is reached');
  }

  if (nextStatus === 'queued' && current.attempts >= current.maxAttempts) {
    throw new Error('cannot retry observation generation job after max_attempts is reached');
  }
}

function mapJobRow(row: JobRow): PostgresObservationGenerationJob {
  return {
    id: row.id,
    projectId: row.project_id,
    teamId: row.team_id,
    agentEventId: row.agent_event_id,
    sourceType: row.source_type,
    sourceId: row.source_id,
    serverSessionId: row.server_session_id,
    jobType: row.job_type,
    status: row.status,

View on GitHub (pinned to d8bc9755e7)