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

  1. Verify the string starts with `data:` and contains a comma separating the mediatype from the payload
  2. Ensure binary payloads use `;base64` and that the base64 is valid (no whitespace/newlines/url-encoding)
  3. Check the MIME type is an image type the service accepts (it casts to ImageType for getExtByMimeType)
  4. If the source is an http URL, do not pass it here — use the URL branch of getUploadableByUrlOrDataUri instead
  5. 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

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


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/e3554f7b9e14e874. Report an issue: GitHub.