{"record":{"id":"e83f5c278c938da9","repo":"yikart/AiToEarn","slug":"invalidworklink-e83f5c","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/threads/threads-work.provider.ts","lineNumber":73,"sourceCode":"        publishedAt: parsePlatformDate(post.timestamp),\n        authorName: post.username,\n        authorPlatformUid: post.owner?.id,\n      })),\n      pagination: {\n        mode: ChannelPaginationMode.Cursor,\n        nextCursor: response.paging?.cursors?.after,\n        previousCursor: response.paging?.cursors?.before,\n        hasNext: Boolean(response.paging?.next),\n        hasPrevious: Boolean(response.paging?.previous),\n        limit,\n      },\n    }\n  }\n\n  async getLinkInfo(input: WorkLinkInfoInput): Promise<ChannelWorkDataResult> {\n    const parsed = this.parseThreadsPostLink(input.link)\n    if (!parsed) {\n      throw new AppException(ResponseCode.InvalidWorkLink)\n    }\n    return {\n      snapshots: [],\n      work: {\n        id: parsed.postId,\n        url: parsed.normalizedUrl,\n      },\n    }\n  }\n\n  async getDetail(input: WorkDetailInput): Promise<ChannelWorkDataResult> {\n    const post = await this.threadsService.getPublishedPost(\n      input.platformWorkId,\n      input.credential.accessToken,\n      'id,status,permalink,text,timestamp,username',\n    )\n    const fetchedAt = new Date()\n    const timestamp = post.timestamp ? new Date(post.timestamp) : undefined","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/threads/threads-work.provider.ts#L55-L91","documentation":"getLinkInfo parses the supplied link with parseThreadsPostLink; if the string doesn't match a Threads post URL shape, parseThreadsPostLink returns null and InvalidWorkLink is thrown. No network call is involved — it's pure URL-shape validation.","triggerScenarios":"Calling threadsWorkProvider.getLinkInfo with a link that parseThreadsPostLink cannot parse — not a threads.net/@user/post/<id> style URL, malformed, or a different platform's URL.","commonSituations":"User pasted a Threads profile or share text instead of a post permalink; URL uses an unexpected locale subdomain or embed format; link is actually from Instagram/X but was routed to the Threads provider.","solutions":["Confirm the input is a Threads post permalink containing a post id (threads.net/<@user>/post/<id>).","Pre-validate the URL shape client-side before dispatching to the Threads provider.","Check parseThreadsPostLink's accepted patterns; normalize short/embed/share URLs to the canonical post permalink form first.","Route non-Threads links to the correct platform's work provider instead."],"exampleFix":"// before\nconst info = await threadsWorkProvider.getLinkInfo({ link: raw })\n// after\nconst isThreadsPost = /threads\\.(net|com)\\/[^/]+\\/post\\/[\\w]+/.test(raw)\nif (!isThreadsPost) throw new Error('Expected a Threads post permalink')\nconst info = await threadsWorkProvider.getLinkInfo({ link: raw })","handlingStrategy":"validation","validationCode":"function isThreadsPostLink(link: string): boolean {\n  return /^https?:\\/\\/(?:www\\.)?threads\\.(?:net|com)\\/[^/]+\\/post\\/[\\w-]+/.test(link)\n}\nif (!isThreadsPostLink(link)) throw new Error('Expected a Threads post permalink (threads.net/<user>/post/<id>)')","typeGuard":"function parseThreadsPostUrl(link: string): { postId: string } | null {\n  const m = link.match(/threads\\.(?:net|com)\\/[^/]+\\/post\\/([\\w-]+)/)\n  return m ? { postId: m[1] } : null\n}","tryCatchPattern":"try {\n  await threadsWorkProvider.getLinkInfo({ link })\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.InvalidWorkLink) {\n    return { ok: false, reason: 'Not a Threads post permalink' }\n  }\n  throw e\n}","preventionTips":["Validate the URL shape client-side before dispatching to a platform provider.","Normalize share text and embed URLs into canonical post permalinks.","Detect the platform from the hostname before choosing a provider.","Keep the accepted-URL regex updated as Threads changes URL formats."],"tags":["validation","url-parsing","threads"],"backgroundTag":"invalid-url","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}