yikart/AiToEarn · warning · AppException

InvalidWorkLink

InvalidWorkLink

Error message

InvalidWorkLink

What it means

getLinkInfo parses a Douyin work (video) link and throws InvalidWorkLink when parseWorkId cannot extract a data/work ID from the normalized URL. It means the provided link is not a recognized Douyin work URL.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-work.provider.ts:17

import type { ChannelWorkDataResult, WorkLinkInfoInput, WorkProvider } from '../platforms.interface'
import { Injectable, Logger } from '@nestjs/common'
import { PublishType } from '@yikart/aitoearn-server-shared'
import { AccountType, AppException, ResponseCode } from '@yikart/common'
import axios from 'axios'
import { buildDouyinVideoWorkLink } from './douyin.interface'

@Injectable()
export class DouyinWorkProvider implements WorkProvider {
  readonly requiresCredentialForLinkInfo = false
  private readonly logger = new Logger(DouyinWorkProvider.name)

  async getLinkInfo(input: WorkLinkInfoInput): Promise<ChannelWorkDataResult> {
    const resolvedUrl = await this.normalizeLink(input.link)
    const dataId = this.parseWorkId(resolvedUrl)
    if (!dataId) {
      throw new AppException(ResponseCode.InvalidWorkLink)
    }

    const url = this.buildWorkLink(dataId, resolvedUrl)
    return {
      snapshots: [],
      work: {
        id: dataId,
        url,
        mediaType: PublishType.VIDEO,
      },
      extra: {
        dataId,
        uniqueId: `${AccountType.Douyin}_${dataId}`,
        type: PublishType.VIDEO,
        videoType: 'short',
        resolvedUrl: url,
      },
      rawResponse: { resolvedUrl },

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Verify the input is a direct Douyin work URL (video detail page containing the work ID)
  2. Extend normalizeLink/parseWorkId regexes to handle the new share-link format seen in production
  3. Ask the user to re-share via the app's 'copy link' so the URL contains the work ID

Example fix

// before
const dataId = this.parseWorkId(resolvedUrl)
if (!dataId) {
  throw new AppException(ResponseCode.InvalidWorkLink)
}
// after
const dataId = this.parseWorkId(resolvedUrl)
if (!dataId) {
  throw new AppException(ResponseCode.InvalidWorkLink, { url: resolvedUrl })
}
Defensive patterns

Strategy: validation

Validate before calling

const DOUYIN_WORK_URL = /douyin\.com\/(video|note)\/(\d+)/
export function extractWorkId(link: string): string | null {
  const m = link.match(DOUYIN_WORK_URL) ?? link.match(/douyin\.com.*[?&]modal_id=(\d+)/)
  return m ? m[1] : null
}
if (!extractWorkId(userLink)) {
  return { ok: false, message: 'Please share a direct Douyin video link' }
}

Type guard

function isDouyinWorkUrl(url: string): boolean {
  return /douyin\.com\/(video|note)\/\d+/.test(url) || /modal_id=\d+/.test(url)
}

Try / catch

try {
  const info = await workProvider.getLinkInfo({ link })
} catch (e) {
  if (e instanceof AppException && e.code === 'InvalidWorkLink') {
    return { ok: false, userMessage: 'This does not look like a Douyin video link. Use share > copy link.' }
  }
  throw e
}

Prevention

When it happens

Trigger: Calling getLinkInfo with a URL whose normalized form doesn't match Douyin work-URL patterns (e.g. user profile page, short-share URL that normalizeLink couldn't resolve, or non-Douyin link).

Common situations: Users pasting share text instead of a URL, new Douyin share-link formats the parser doesn't recognize, shortened links requiring an HTTP resolution step that failed or was skipped, or private/deleted works whose pages no longer resolve to an ID.

Related errors


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