yikart/AiToEarn · error · CustomErrorOrNull

ERR_CODE_OR_NULL

ERR_CODE_OR_NULL

Error message

PublishRecordNotFound

What it means

getByFlowId looks up the publish record for a publish flow by calling listByFlowId (local DB first, then relay records). If the returned list is empty — no record exists locally for (userId, flowId) and none came back from the relay — it throws AppException(ResponseCode.PublishRecordNotFound). This signals that no publish record is associated with the given flow ID for that user.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/publish/records/publish-record-read.service.ts:44

    private readonly publishRecordRepo: PublishRecordRepository,
    private readonly accountRepository: AccountRepository,
    private readonly workService: WorkService,
    @Optional() private readonly relayClientService?: RelayClientService,
  ) {}

  async listByFlowId(userId: string, flowId: string) {
    const localRecords = await this.publishRecordRepo.listByFlowIdAndUserId(flowId, userId)
    if (localRecords.length > 0) {
      return localRecords
    }
    return this.listRelayRecords(userId, '/v2/channels/publish/records', { flowId })
  }

  async getByFlowId(userId: string, flowId: string) {
    const records = await this.listByFlowId(userId, flowId)
    const record = records[0]
    if (!record) {
      throw new AppException(ResponseCode.PublishRecordNotFound)
    }
    return record
  }

  async listByUserId(userId: string, query?: {
    accountId?: string
    accountType?: AccountType
    flowId?: string
    source?: PublishRecordSource
    status?: PublishStatus
    type?: PublishType
    time?: [Date, Date]
    uid?: string
  }) {
    const localRecords = await this.publishRecordRepo.listByFilter({
      userId,
      ...query,
    })

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Verify the flowId is the one returned when the publish flow was created and belongs to the same user.
  2. List records via listByUserId/listByFlowId first to confirm the record exists before calling getByFlowId.
  3. Check that RelayClientService.enabled is true if records may live on the relay side.
  4. If the record should exist, inspect the publish_records collection for { userId, flowId } and re-run the publish flow if missing.

Example fix

// before
const record = await service.getByFlowId(userId, flowId)
// after
const records = await service.listByFlowId(userId, flowId)
if (!records.length) {
  // handle gracefully: record not ready or unknown flowId
  return null
}
const record = records[0]
Defensive patterns

Strategy: validation

Validate before calling

const records = await service.listByFlowId(userId, flowId)
if (!records.length) throw new NotFoundError(`No publish record for flow ${flowId}`)
const record = records[0]

Type guard

function hasRecord<T>(arr: T[]): arr is [T, ...T[]] {
  return arr.length > 0
}

Try / catch

try {
  const record = await service.getByFlowId(userId, flowId)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.PublishRecordNotFound) {
    return null // flow not ready or unknown
  }
  throw e
}

Prevention

When it happens

Trigger: Calling getByFlowId with a flowId that never produced a publish record, a flowId belonging to a different userId, a typo'd/stale flowId, or relay disabled/unreachable while the record only exists on the relay side.

Common situations: Client polls publish status before the record has been created; the record was deleted after completion; multi-environment setups where the flow ran on the relay (aitoearn.ai/aitoearn.cn) but the local relay client is not enabled; copying a flowId from another environment.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/c8d7aae7775f39ec. Report an issue: GitHub.