yikart/AiToEarn · warning · BadRequestException
Invalid data URI
Error message
Invalid data URI
What it means
getUploadableByDataUri converts a data URI string into a Uploadable file object for the AI SDK. It uses the WHATWG data-urls parser, which strictly requires the format `data:[<mediatype>][;base64],<data>` with a supported MIME type. If parseDataUri returns null the URI is not a valid data URL (or uses an unsupported scheme/mediatype) and this BadRequestException is thrown.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/image/image.service.ts:63
return modelConfig?.runtimeModel ?? model
}
private getImageModelRetry(model: string, kind: 'generation' | 'edit'): number {
const modelConfig = kind === 'generation'
? this.modelsConfigService.config.image.generation.find(item => item.name === model)
: this.modelsConfigService.config.image.edit.find(item => item.name === model)
return modelConfig?.retry ?? 0
}
/**
* 将 data uri 转换为 Uploadable
*/
private getUploadableByDataUri(dataUri: string, filename = 'image'): Uploadable {
const file = parseDataUri(dataUri)
if (file == null) {
throw new BadRequestException('Invalid data URI')
}
const ext = getExtByMimeType(file.mimeType.essence as ImageType)
return new File([file.body as Uint8Array<ArrayBuffer>], `${filename}.${ext}`, { type: file.mimeType.essence })
}
/**
* 将 URL 转换为 Uploadable
*/
private async getUploadableByUrl(url: string): Promise<Uploadable> {
return await fetch(url)
}
/**
* 将 URL 或 Data URI 转换为 Uploadable
*/
private async getUploadableByUrlOrDataUri(urlOrDataUri: string, filename = 'image'): Promise<Uploadable> {
if (/^https?:\/\//.test(urlOrDataUri)) {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Verify the string starts with `data:` and contains a comma separating the mediatype from the payload
- Ensure binary payloads use `;base64` and that the base64 is valid (no whitespace/newlines/url-encoding)
- Check the MIME type is an image type the service accepts (it casts to ImageType for getExtByMimeType)
- If the source is an http URL, do not pass it here — use the URL branch of getUploadableByUrlOrDataUri instead
- Log a prefix of the failing string to detect truncation by upstream clients
Example fix
// before
const uploadable = imageService.getUploadableByUrlOrDataUri(rawBase64)
// after
const dataUri = rawBase64.startsWith('data:') ? rawBase64 : `data:image/png;base64,${rawBase64}`
const uploadable = imageService.getUploadableByUrlOrDataUri(dataUri) Defensive patterns
Strategy: validation
Validate before calling
function isImageDataUri(s: string): boolean {
return /^data:image\/[a-z0-9.+-]+(;base64)?,/i.test(s)
}
// call before: if (!isImageDataUri(input)) throw new BadRequestException('expected a data:image/... URI') Type guard
function isDataUri(v: unknown): v is `data:${string}` {
return typeof v === 'string' && v.startsWith('data:') && v.includes(',')
} Try / catch
try {
const uploadable = getUploadableByUrlOrDataUri(input)
} catch (e) {
if (e instanceof BadRequestException && e.message === 'Invalid data URI') {
throw new BadRequestException('Image must be a valid data:image/...;base64,... URI or an http(s) URL')
}
throw e
} Prevention
- Always send base64 payloads wrapped as `data:image/png;base64,...`, never raw base64
- Never pass http(s) URLs into the data-URI branch
- Validate with a regex prefix check before calling the API
- Watch for clients truncating long data URIs in logs or payloads
When it happens
Trigger: Caller passes getUploadableByUrlOrDataUri a string that is not a well-formed data URI: missing the `data:` prefix or comma separator, no base64/plain marker, URL-encoded or otherwise mangled base64 payload, an exotic mediatype the parser rejects, or the caller mislabels a plain base64 string / http URL as a data URI.
Common situations: Clients sending base64 image payloads without the data URI envelope; frontend code that strips or corrupts the prefix; a field containing an http(s) URL routed into the data-URI branch; copying a data URI truncated by logs or message-size limits.
Related errors
- InvalidWorkLink
- No subtitle entries in response
- No response from Gemini
- Invalid subtitle data: ${z.prettifyError(result.error)}
- Canvas not provided and no vid:// video source found in Trac
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/e3554f7b9e14e874.
Report an issue: GitHub.