{"record":{"id":"848aeef5fba5e1a2","repo":"yikart/AiToEarn","slug":"invalidworklink-848aee","errorCode":"InvalidWorkLink","errorMessage":"InvalidWorkLink","messagePattern":"InvalidWorkLink","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"warning","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/pinterest/pinterest-work.provider.ts","lineNumber":56,"sourceCode":"        url: buildPinterestPinWorkLink(pin.id),\n        coverUrl: pin.media?.images?.['1200x']?.url,\n        publishedAt: parsePlatformDate(pin.created_at),\n      })),\n      pagination: {\n        mode: ChannelPaginationMode.Cursor,\n        nextCursor: response.bookmark,\n        hasNext: Boolean(response.bookmark),\n        hasPrevious: false,\n        limit,\n      },\n    }\n  }\n\n  async getLinkInfo(input: WorkLinkInfoInput): Promise<ChannelWorkDataResult> {\n    const resolvedUrl = await this.normalizeLink(input.link)\n    const pinId = this.parsePinterestPinId(resolvedUrl)\n    if (!pinId) {\n      throw new AppException(ResponseCode.InvalidWorkLink)\n    }\n    const url = buildPinterestPinWorkLink(pinId)\n    return {\n      snapshots: [],\n      work: {\n        id: pinId,\n        url,\n      },\n      extra: {\n        dataId: pinId,\n        uniqueId: `${input.platform}_${pinId}`,\n        resolvedUrl,\n      },\n      rawResponse: { resolvedUrl },\n    }\n  }\n\n  async getDetail(input: WorkDetailInput): Promise<ChannelWorkDataResult> {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/pinterest/pinterest-work.provider.ts#L38-L74","documentation":"InvalidWorkLink is thrown by PinterestWorkProvider.getLinkInfo when the link cannot be parsed into a Pinterest pin ID. After normalizing the URL (resolving redirects), parsePinterestPinId returns null, meaning the URL does not match a Pinterest pin URL pattern.","triggerScenarios":"Calling getLinkInfo({ link }) with a URL that is not a Pinterest pin link (wrong domain, a profile/board URL, or a short link whose redirect target still contains no pin id).","commonSituations":"Users paste pinterest.com profile or board URLs instead of a pin URL; links from other platforms pasted into a Pinterest channel; localized/redirected URLs with unexpected formats.","solutions":["Ensure the link is a pin URL matching the pin-id pattern (e.g. https://www.pinterest.com/pin/<id>/ or pin.it short link that resolves to one)","Open the link in a browser and copy the canonical pin URL","Check that pin.it short links resolve successfully (see error 207 for redirect failures)"],"exampleFix":"// before\nawait provider.getLinkInfo({ link: 'https://www.pinterest.com/myprofile/' }) // no pin id -> InvalidWorkLink\n// after\nawait provider.getLinkInfo({ link: 'https://www.pinterest.com/pin/123456789012345678/' })","handlingStrategy":"validation","validationCode":"const PIN_RE = /^https?:\\/\\/([a-z]+\\.)?pinterest\\.com\\/pin\\/(\\d+)/i\nfunction isPinterestPinUrl(link: string): boolean { return PIN_RE.test(link.trim()) }\nif (!isPinterestPinUrl(link) && !/^https?:\\/\\/pin\\.it\\//i.test(link)) throw new Error('Provide a Pinterest pin URL')","typeGuard":"function extractPinId(url: string): string | null {\n  const m = url.match(/pinterest\\.com\\/pin\\/(\\d+)/i)\n  return m ? m[1] : null\n}","tryCatchPattern":"try {\n  const info = await provider.getLinkInfo({ link })\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.InvalidWorkLink) {\n    // show 'This does not look like a Pinterest pin link'\n  } else throw e\n}","preventionTips":["Use pin URLs (pinterest.com/pin/<id>/) not profile/board URLs","Validate URL shape client-side before calling getLinkInfo","Ensure short links resolve to pin URLs (deleted pins will not)","Handle regional Pinterest domains in your own validation"],"tags":["pinterest","url-parsing","input-validation"],"backgroundTag":"invalid-work-link","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}