yikart/AiToEarn · error · AppException

InvalidWorkLink

InvalidWorkLink

Error message

InvalidWorkLink

What it means

RedNote publish requires input.option.workLink: without it there is no source note to publish from, so the provider throws InvalidWorkLink before doing any work. It is a synchronous input-validation error thrown from the publish entry point.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/rednote/rednote-publish.provider.ts:66

          params: { field: PublishValidationField.Option },
        }],
      }
    }

    return { valid: true }
  }

  async normalize(input: PublishNormalizeInput<RedNoteOption>): Promise<NormalizedPublishTask<RedNoteOption>> {
    return {
      content: input.content,
      option: input.option,
    }
  }

  async publish(input: PublishPublishInput<RedNoteOption>): Promise<PublishProviderResult<RedNoteDataOption>> {
    const workLink = input.option?.workLink
    if (!workLink) {
      throw new AppException(ResponseCode.InvalidWorkLink)
    }

    const workLinkInfo = await this.workProvider.getWorkLinkInfo(workLink)
    const extra = workLinkInfo.extra

    return {
      status: 200,
      platformWorkId: extra.dataId,
      permalink: extra.resolvedUrl ?? workLink,
      originalWorkLink: extra.originalWorkLink,
      workStatus: extra.workStatus,
      dataOption: {
        dataId: extra.dataId,
        uniqueId: extra.uniqueId,
      },
    }
  }
}

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Ensure the publishing request includes option.workLink with the full RedNote note URL.
  2. Validate the input payload at the API/job boundary before invoking publish (require non-empty workLink for RedNote).
  3. Check where the PublishPublishInput is constructed in your flow — the workLink is likely dropped during serialization or option construction.

Example fix

// before
await provider.publish({ ...rest, option: undefined })
// after
if (!rest.option?.workLink) {
  throw new Error('RedNote publish requires option.workLink')
}
await provider.publish({ ...rest, option: rest.option })
Defensive patterns

Strategy: validation

Validate before calling

function assertRedNotePublishInput(input: PublishPublishInput<RedNoteOption>) {
  if (!input.option?.workLink) {
    throw new Error('RedNote publish requires a non-empty option.workLink')
  }
}

Type guard

function hasWorkLink(opt: RedNoteOption | undefined | null): opt is RedNoteOption & { workLink: string } {
  return typeof opt?.workLink === 'string' && opt.workLink.length > 0
}

Try / catch

try {
  await provider.publish(input)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.InvalidWorkLink) {
    return { ok: false, reason: 'missing workLink in publish option' }
  }
  throw e
}

Prevention

When it happens

Trigger: Calling rednotePublishProvider.publish with input.option undefined, or option present but option.workLink missing/null/empty.

Common situations: Caller builds PublishPublishInput without populating the RedNote-specific option; upstream job lost the workLink field; caller confused workLink with a plain note URL stored elsewhere; schema change on the producer side dropped the field.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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