{"record":{"id":"33bc3591841cd38f","repo":"yikart/AiToEarn","slug":"invalidworklink-33bc35","errorCode":"InvalidWorkLink","errorMessage":"InvalidWorkLink","messagePattern":"InvalidWorkLink","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/rednote/rednote-work.provider.ts","lineNumber":32,"sourceCode":"  workStatus?: WorkStatus\n} & Record<string, string | PublishType | WorkStatus | undefined>\n\nexport type RedNoteWorkLinkInfoResult = ChannelWorkDataResult<RedNoteWorkLinkExtra> & { extra: RedNoteWorkLinkExtra }\n\n@Injectable()\nexport class RedNoteWorkProvider implements WorkProvider {\n  readonly requiresCredentialForLinkInfo = false\n  private readonly logger = new Logger(RedNoteWorkProvider.name)\n\n  async getLinkInfo(input: WorkLinkInfoInput): Promise<ChannelWorkDataResult> {\n    return this.getWorkLinkInfo(input.link, input.dataId)\n  }\n\n  async getWorkLinkInfo(workLink: string, dataId?: string): Promise<RedNoteWorkLinkInfoResult> {\n    const parsed = await this.parseRedNoteUrl(workLink)\n    const resolvedDataId = parsed.noteId || dataId || ''\n    if (!resolvedDataId) {\n      throw new AppException(ResponseCode.InvalidWorkLink)\n    }\n\n    const resolvedUrl = parsed.resolvedUrl ?? workLink\n    const extra: RedNoteWorkLinkExtra = {\n      dataId: resolvedDataId,\n      uniqueId: `${AccountType.RedNote}_${resolvedDataId}`,\n      type: PublishType.VIDEO,\n      videoType: 'short',\n      resolvedUrl,\n      originalWorkLink: resolvedUrl !== workLink ? workLink : undefined,\n      workStatus: parsed.noteId && !parsed.xsecToken ? WorkStatus.LINK_ERROR : undefined,\n    }\n\n    return {\n      work: {\n        id: resolvedDataId,\n        url: resolvedUrl,\n        mediaType: PublishType.VIDEO,","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/rednote/rednote-work.provider.ts#L14-L50","documentation":"getWorkLinkInfo parses the RedNote URL to extract a noteId, optionally falling back to the dataId argument. If neither parseRedNoteUrl yields a noteId nor a dataId is supplied, the link cannot be identified and InvalidWorkLink is thrown.","triggerScenarios":"Calling getWorkLinkInfo (directly or via getLinkInfo) with a string that is not a recognizable RedNote note URL (no note id in path/query), and no dataId fallback passed.","commonSituations":"User pasted a RedNote homepage/profile/search URL instead of a note link; short-link or share-text format that parseRedNoteUrl doesn't handle; link to a deleted/private note that returns no id; mobile share URL variant not matching the parse regex.","solutions":["Verify the input is a direct RedNote note URL containing a note id (e.g. xiaohongshu.com/explore/<id> or /discovery/item/<id>).","If you have the note id from another source, pass it as the dataId argument so the parse result isn't required.","Inspect parseRedNoteUrl's accepted URL patterns and normalize the user-supplied share text/short link to a supported format before calling.","Ask the user to re-copy the share link via the RedNote app's 'copy link' action."],"exampleFix":"// before\nconst info = await workProvider.getWorkLinkInfo(userInput)\n// after\nconst noteId = userInput.match(/(?:explore|discovery\\/item)\\/([0-9a-f]+)/)?.[1]\nif (!noteId) throw new Error('Not a RedNote note link')\nconst info = await workProvider.getWorkLinkInfo(userInput, noteId)","handlingStrategy":"validation","validationCode":"const NOTE_ID_RE = /(?:explore|discovery\\/item)\\/([0-9a-zA-Z]+)/\nfunction isRedNoteNoteLink(link: string): boolean {\n  return NOTE_ID_RE.test(link)\n}\nif (!isRedNoteNoteLink(link) && !dataId) throw new Error('Provide a RedNote note URL or a dataId')","typeGuard":"function isRedNoteNoteLink(link: string): link is string {\n  return /xiaohongshu\\.com\\/.+(?:explore|discovery\\/item)\\/[0-9a-zA-Z]+/.test(link)\n}","tryCatchPattern":"try {\n  await workProvider.getWorkLinkInfo(link)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.InvalidWorkLink) {\n    return { ok: false, reason: 'URL is not a RedNote note link and no dataId was provided' }\n  }\n  throw e\n}","preventionTips":["Pre-validate user-pasted URLs against the known note URL patterns.","Normalize share texts/short links before calling getWorkLinkInfo.","Pass the extracted note id as dataId when available.","Reject non-note URLs (profile/search/homepage) at the UI layer."],"tags":["validation","url-parsing","rednote"],"backgroundTag":"invalid-url","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}