yikart/AiToEarn · warning
InvalidUrl
InvalidUrl
Error message
Failed to probe image ${m.url} What it means
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.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/media/media.service.ts:396
allowUnknownFormat: mediaType === PublishMediaType.Video && !urlExtension,
}))
}
catch (err) {
this.logger.warn(err, `Failed to probe video ${m.url}`)
issues.push({
code: PublishValidationIssueCode.InvalidUrl,
path: pathPrefix,
params: { field: PublishValidationField.Video, url: m.url },
})
}
}
else {
try {
const probe = await this.probeImage(m.url)
issues.push(...this.validateImage(probe, rules, pathPrefix))
}
catch (err) {
this.logger.warn(err, `Failed to probe image ${m.url}`)
issues.push({
code: PublishValidationIssueCode.InvalidUrl,
path: pathPrefix,
params: { field: PublishValidationField.Image, url: m.url },
})
}
}
}
if (content.cover?.url) {
const pathPrefix = ['content', 'cover']
try {
const probe = await this.probeImage(content.cover.url)
issues.push(...this.validateImage(probe, rules, pathPrefix))
}
catch (err) {
this.logger.warn(err, `Failed to probe cover ${content.cover.url}`)
issues.push({
code: PublishValidationIssueCode.InvalidUrl,View on GitHub (pinned to d3aa8bea5b)
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.
Example fix
// before
url: 'https://cdn.example.com/tmp/abc?X-Amz-Expires=60'
// after: issue a long-lived public URL before validation
url: await storage.getPublicUrl(key, { expiresIn: '24h' }) Defensive patterns
Strategy: validation
Validate before calling
// Before calling validateMedia, ensure each media URL is fetchable
async function assertImageFetchable(url: string) {
const res = await fetch(url, { method: 'HEAD' })
if (!res.ok) throw new Error(`URL not fetchable: ${url} (${res.status})`)
const ct = res.headers.get('content-type') ?? ''
if (!ct.startsWith('image/')) throw new Error(`Not an image: ${url} (${ct})`)
} Type guard
function hasValidUrl(m: { url?: string }): m is { url: string } {
return typeof m.url === 'string' && /^https:\/\//.test(m.url)
} Try / catch
const issues = await mediaService.validateMedia(content, rules)
if (issues.some(i => i.code === PublishValidationIssueCode.InvalidUrl)) {
// surface bad URLs (issue.params.url) back to the user for re-upload
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- Failed to fetch image: ${response.status} ${response.statusT
- Relay uploadSign returned no uploadUrl: ${JSON.stringify(sig
- S3DownloadFileFailed
- ChannelPlatformMediaProcessingFailed
- ChannelPlatformMediaProcessingFailed
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/a694e78cd9685acf.
Report an issue: GitHub.