{"record":{"id":"a694e78cd9685acf","repo":"yikart/AiToEarn","slug":"invalidurl","errorCode":"InvalidUrl","errorMessage":"Failed to probe image ${m.url}","messagePattern":"Failed to probe image (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/media/media.service.ts","lineNumber":396,"sourceCode":"            allowUnknownFormat: mediaType === PublishMediaType.Video && !urlExtension,\n          }))\n        }\n        catch (err) {\n          this.logger.warn(err, `Failed to probe video ${m.url}`)\n          issues.push({\n            code: PublishValidationIssueCode.InvalidUrl,\n            path: pathPrefix,\n            params: { field: PublishValidationField.Video, url: m.url },\n          })\n        }\n      }\n      else {\n        try {\n          const probe = await this.probeImage(m.url)\n          issues.push(...this.validateImage(probe, rules, pathPrefix))\n        }\n        catch (err) {\n          this.logger.warn(err, `Failed to probe image ${m.url}`)\n          issues.push({\n            code: PublishValidationIssueCode.InvalidUrl,\n            path: pathPrefix,\n            params: { field: PublishValidationField.Image, url: m.url },\n          })\n        }\n      }\n    }\n    if (content.cover?.url) {\n      const pathPrefix = ['content', 'cover']\n      try {\n        const probe = await this.probeImage(content.cover.url)\n        issues.push(...this.validateImage(probe, rules, pathPrefix))\n      }\n      catch (err) {\n        this.logger.warn(err, `Failed to probe cover ${content.cover.url}`)\n        issues.push({\n          code: PublishValidationIssueCode.InvalidUrl,","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/media/media.service.ts#L378-L414","documentation":"During validateMedia, a non-video media entry is fetched with probeImage to check dimensions/format against platform rules. If probeImage throws (unreachable URL, non-image content, timeout, oversized body), the error is logged as 'Failed to probe image <url>' and a PublishValidationIssue with code InvalidUrl is appended instead of failing the request.","triggerScenarios":"content.media[i].url points to a dead/hostile URL: 404/410 from expired CDN link, DNS failure, non-2xx response, response Content-Type not an image, body exceeds probe size limits, or TLS error.","commonSituations":"Presigned upload URLs expired before publishing; client submitted a placeholder or localhost URL; storage bucket object deleted; image host blocks the server's user-agent/region; wrong file extension causing video/image branch confusion is irrelevant here (this branch is the non-video fallback).","solutions":["Fix or re-upload the media at the failing URL reported in the issue params.url, then re-submit validation.","Verify the URL is publicly reachable (curl -I) and serves an image content type with no auth required.","If the file is actually a video, ensure the media type/extension classifies it as video so the video probe path runs.","Extend media URL TTL or move files to stable storage before calling validateMedia."],"exampleFix":"// before\nurl: 'https://cdn.example.com/tmp/abc?X-Amz-Expires=60'\n// after: issue a long-lived public URL before validation\nurl: await storage.getPublicUrl(key, { expiresIn: '24h' })","handlingStrategy":"validation","validationCode":"// Before calling validateMedia, ensure each media URL is fetchable\nasync function assertImageFetchable(url: string) {\n  const res = await fetch(url, { method: 'HEAD' })\n  if (!res.ok) throw new Error(`URL not fetchable: ${url} (${res.status})`)\n  const ct = res.headers.get('content-type') ?? ''\n  if (!ct.startsWith('image/')) throw new Error(`Not an image: ${url} (${ct})`)\n}","typeGuard":"function hasValidUrl(m: { url?: string }): m is { url: string } {\n  return typeof m.url === 'string' && /^https:\\/\\//.test(m.url)\n}","tryCatchPattern":"const issues = await mediaService.validateMedia(content, rules)\nif (issues.some(i => i.code === PublishValidationIssueCode.InvalidUrl)) {\n  // surface bad URLs (issue.params.url) back to the user for re-upload\n}","preventionTips":["Use long-lived or public URLs for media; refresh presigned URLs before publishing.","HEAD-check every media URL client-side before submit.","Ensure media is fully uploaded/transcoded before triggering validation.","Host media on stable storage reachable from the server network."],"tags":["media","image","url-validation","network"],"backgroundTag":"media-url-unreachable","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}