{"record":{"id":"39e0c0f1976c6a53","repo":"yikart/AiToEarn","slug":"err-code-or-null-39e0c0","errorCode":"ERR_CODE_OR_NULL","errorMessage":"ChannelPublishQueueRemoveFailed","messagePattern":"ChannelPublishQueueRemoveFailed","errorType":"exception","errorClass":"CustomErrorOrNull","httpStatus":500,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/publish/tasks/publish-task.service.ts","lineNumber":408,"sourceCode":"        : { category: PlatformErrorCategory.Unknown, retryable: false }\n      await this.stateService.markUpdatedFailed(taskId, {\n        category: error.category,\n        code: error.code,\n        message: this.getErrorMessage(err, ResponseCode.PublishTaskUpdateFailed),\n        originalData: error.originalData,\n        retryable: error.retryable,\n        occurredAt: new Date(),\n      })\n    }\n  }\n\n  async cancelTask(userId: string, taskId: string): Promise<void> {\n    const record = await this.getTaskForUser(taskId, userId)\n\n    if (record.status === PublishStatus.Queued) {\n      const removed = await this.queueService.removeJob(taskId)\n      if (!removed) {\n        throw new AppException(ResponseCode.ChannelPublishQueueRemoveFailed)\n      }\n    }\n\n    if (record.status === PublishStatus.PlatformScheduled && record.platformWorkId) {\n      const platformWorkId = record.platformWorkId\n      const { provider } = this.getPublishRuntime(record.accountType)\n      if (provider.cancel) {\n        const account = await this.getRecordAccount(record)\n        const result = await this.runWithCredentialRefresh(account, record.userId, credential => provider.cancel!({\n          taskId,\n          platform: record.accountType,\n          platformWorkId,\n          credential: this.toPublishCredential(credential, account),\n        }))\n        if (!result.canceled) {\n          throw new AppException(ResponseCode.ChannelPublishPlatformCancelFailed)\n        }\n      }","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/publish/tasks/publish-task.service.ts#L390-L426","documentation":"cancelTask calls queueService.removeJob(taskId) when the record is in PublishStatus.Queued. If the queue reports the job could not be removed (removed falsy) it throws ChannelPublishQueueRemoveFailed — the pending job stayed or disappeared in an unexpected way.","triggerScenarios":"Cancelling a Queued task whose BullMQ job cannot be removed — typically because the job already started/was picked up by a worker (status is stale) or the queue backend is unavailable.","commonSituations":"Race between the status snapshot and actual queue state (job moved to active just before cancel); Redis connectivity problems; job already drained but the DB status not yet updated.","solutions":["Refresh the record status and retry the cancel — the task likely already left Queued","Check queue (Redis) connectivity and worker activity","If the task is already running, wait for completion and then cancel via the platform path if supported"],"exampleFix":"// before\nawait taskService.cancelTask(userId, taskId) // status snapshot said Queued\n// after\nconst fresh = await taskService.getTaskForUser(taskId, userId)\nif (fresh.status === PublishStatus.Queued) {\n  await taskService.cancelTask(userId, taskId)\n} else { /* handle running/terminal state */ }","handlingStrategy":"try-catch","validationCode":"const fresh = await taskService.getTaskForUser(taskId, userId)\nif (fresh.status !== 'queued') throw new Error('task no longer queued; cancel path differs')","typeGuard":null,"tryCatchPattern":"try {\n  await taskService.cancelTask(userId, taskId)\n} catch (e) {\n  if (e.code === 'ChannelPublishQueueRemoveFailed') {\n    // refresh status; job likely already active — retry or wait for completion\n  } else throw e\n}","preventionTips":["Re-read task status immediately before canceling","Verify Redis/queue health before cancel operations","Avoid canceling tasks at the exact moment they are being dispatched"],"tags":["queue","cancel","race-condition","bullmq"],"backgroundTag":"queue-job-remove-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}