{"record":{"id":"c8d7aae7775f39ec","repo":"yikart/AiToEarn","slug":"err-code-or-null-c8d7aa","errorCode":"ERR_CODE_OR_NULL","errorMessage":"PublishRecordNotFound","messagePattern":"PublishRecordNotFound","errorType":"exception","errorClass":"CustomErrorOrNull","httpStatus":404,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/publish/records/publish-record-read.service.ts","lineNumber":44,"sourceCode":"    private readonly publishRecordRepo: PublishRecordRepository,\n    private readonly accountRepository: AccountRepository,\n    private readonly workService: WorkService,\n    @Optional() private readonly relayClientService?: RelayClientService,\n  ) {}\n\n  async listByFlowId(userId: string, flowId: string) {\n    const localRecords = await this.publishRecordRepo.listByFlowIdAndUserId(flowId, userId)\n    if (localRecords.length > 0) {\n      return localRecords\n    }\n    return this.listRelayRecords(userId, '/v2/channels/publish/records', { flowId })\n  }\n\n  async getByFlowId(userId: string, flowId: string) {\n    const records = await this.listByFlowId(userId, flowId)\n    const record = records[0]\n    if (!record) {\n      throw new AppException(ResponseCode.PublishRecordNotFound)\n    }\n    return record\n  }\n\n  async listByUserId(userId: string, query?: {\n    accountId?: string\n    accountType?: AccountType\n    flowId?: string\n    source?: PublishRecordSource\n    status?: PublishStatus\n    type?: PublishType\n    time?: [Date, Date]\n    uid?: string\n  }) {\n    const localRecords = await this.publishRecordRepo.listByFilter({\n      userId,\n      ...query,\n    })","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/publish/records/publish-record-read.service.ts#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the flowId is the one returned when the publish flow was created and belongs to the same user.","List records via listByUserId/listByFlowId first to confirm the record exists before calling getByFlowId.","Check that RelayClientService.enabled is true if records may live on the relay side.","If the record should exist, inspect the publish_records collection for { userId, flowId } and re-run the publish flow if missing."],"exampleFix":"// before\nconst record = await service.getByFlowId(userId, flowId)\n// after\nconst records = await service.listByFlowId(userId, flowId)\nif (!records.length) {\n  // handle gracefully: record not ready or unknown flowId\n  return null\n}\nconst record = records[0]","handlingStrategy":"validation","validationCode":"const records = await service.listByFlowId(userId, flowId)\nif (!records.length) throw new NotFoundError(`No publish record for flow ${flowId}`)\nconst record = records[0]","typeGuard":"function hasRecord<T>(arr: T[]): arr is [T, ...T[]] {\n  return arr.length > 0\n}","tryCatchPattern":"try {\n  const record = await service.getByFlowId(userId, flowId)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.PublishRecordNotFound) {\n    return null // flow not ready or unknown\n  }\n  throw e\n}","preventionTips":["Store the flowId returned at publish-flow creation and reuse it verbatim.","Check record existence with the list endpoint before the singular get.","Keep the relay client enabled if your records may live on the relay.","Never reuse flowIds across users or environments."],"tags":["publish-record","not-found","data-lookup"],"backgroundTag":"publish-record-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}