{"record":{"id":"953ec7055b0b2aee","repo":"yikart/AiToEarn","slug":"channelplatformresponseinvalid-953ec7","errorCode":"ChannelPlatformResponseInvalid","errorMessage":"Failed to fetch permalink for media ${mediaId}","messagePattern":"Failed to fetch permalink for media (.+?)","errorType":"exception","errorClass":"InstagramPlatformException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/instagram/instagram-publish.provider.ts","lineNumber":492,"sourceCode":"            raw: lastStatus,\n          },\n          retryable: true,\n        }),\n      },\n    )\n  }\n\n  private async fetchPermalink(\n    accessToken: string,\n    mediaId: string,\n  ): Promise<string> {\n    try {\n      const mediaInfo = await this.instagramService.getMediaInfo(accessToken, mediaId)\n      if (mediaInfo.permalink)\n        return mediaInfo.permalink\n    }\n    catch (err) {\n      this.logger.warn(err, `Failed to fetch permalink for media ${mediaId}`)\n    }\n    throw InstagramPlatformException.validation({\n      code: ResponseCode.ChannelPlatformResponseInvalid,\n      category: PlatformErrorCategory.PlatformUnavailable,\n      context: {\n        endpoint: 'fetchPermalink',\n        platformWorkId: mediaId,\n      },\n    })\n  }\n\n  private isImage(media: PublishMediaInput): boolean {\n    if (media.metadata?.type === PublishMediaType.Image)\n      return true\n    if (media.metadata?.type === PublishMediaType.Video)\n      return false\n    return hasUrlPathExtension(media.url, ['.jpg', '.jpeg'])\n  }","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/instagram/instagram-publish.provider.ts#L474-L510","documentation":"InstagramPublishProvider.fetchPermalink calls instagramService.getMediaInfo to read mediaInfo.permalink for a published IG media item. If the Graph API call fails or the response has no permalink, it logs 'Failed to fetch permalink for media <mediaId>' and throws InstagramPlatformException.validation with code ChannelPlatformResponseInvalid (category PlatformUnavailable, endpoint fetchPermalink). Raised via permalink(), typically after publishing to return the post URL.","triggerScenarios":"getMediaInfo returns an error (expired/insufficient-scope access token, IG account not linked to a FB page, media still processing and lacking permalink yet), the API responds without a permalink field, or a transient Graph API outage occurs.","commonSituations":"Long-lived token expired or user deauthorized the app; requesting permalink immediately after publish before Instagram finishes processing the media; IG professional account demoted/re-linked; Graph API partial outages.","solutions":["Retry after a short delay — permalink may not be available until Instagram finishes processing the just-published media.","Reconnect the Instagram channel to refresh the access token; verify scopes include instagram_basic/instagram_manage_insights.","Check the logged inner error for Graph API error_subcode and handle 190 (token invalid) via channel re-auth flow.","If the media was deleted on Instagram, treat as permanent failure and surface a platform-unavailable message."],"exampleFix":"// before: fetch immediately after publish\nconst url = await provider.permalink(mediaId) // media processing -> ChannelPlatformResponseInvalid\n// after\nawait delay(30_000)\nconst url = await provider.permalink(mediaId)","handlingStrategy":"retry","validationCode":"// Verify token validity before fetching permalink\nconst isValid = await instagramService.validateToken(accessToken)\nif (!isValid) throw new Error('Instagram token expired; reconnect channel')","typeGuard":"function isInstagramPlatformException(e: unknown): e is InstagramPlatformException {\n  return e instanceof InstagramPlatformException\n}","tryCatchPattern":"async function permalinkWithRetry(provider, mediaId, attempts = 3) {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      return await provider.permalink(mediaId)\n    } catch (e) {\n      if (i === attempts - 1) throw e\n      await new Promise(r => setTimeout(r, 30_000 * (i + 1))) // media may still be processing\n    }\n  }\n}","preventionTips":["Delay permalink retrieval after publish until Instagram finishes processing the media.","Refresh long-lived tokens before expiry and detect error code 190 to trigger re-auth.","Confirm scopes (instagram_basic) at channel connect time.","Treat permanent failures (deleted media) distinctly from transient PlatformUnavailable."],"tags":["instagram","graph-api","permalink","token-expired","platform-unavailable"],"backgroundTag":"platform-api-response-invalid","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}