siyuan-note/siyuan · error

generated image is invalid

Error message

generated image is invalid

What it means

Thrown by ValidateGeneratedImage (kernel/util/openai.go:717) after the MIME check passes but image.DecodeConfig fails, or the decoded dimensions are out of bounds: width/height must be 1..16384 and width*height must not exceed maxGeneratedImagePixels (100 * 1000 * 1000, ~100MP). It catches corrupt, truncated, or absurdly large images that nonetheless sniff as a valid PNG/JPEG/WebP.

Source

Thrown at kernel/util/openai.go:717

	}
	if len(data) > maxGeneratedImageBytes {
		return "", "", errors.New("generated image exceeds size limit")
	}
	mimeType = mimetype.Detect(data).String()
	switch mimeType {
	case "image/png":
		extension = ".png"
	case "image/jpeg":
		extension = ".jpg"
	case "image/webp":
		extension = ".webp"
	default:
		return "", "", fmt.Errorf("unsupported generated image type: %s", mimeType)
	}
	config, _, decodeErr := image.DecodeConfig(bytes.NewReader(data))
	if decodeErr != nil || config.Width < 1 || config.Height < 1 || config.Width > 16384 || config.Height > 16384 ||
		int64(config.Width)*int64(config.Height) > maxGeneratedImagePixels {
		return "", "", errors.New("generated image is invalid")
	}
	return mimeType, extension, nil
}

func NewOpenAIImageAdapter(apiKey, apiBaseURL, model string, timeout int) *OpenAIImageAdapter {
	if timeout < 1 {
		timeout = 30
	}
	return &OpenAIImageAdapter{
		client:  NewOpenAIClientWithModel(apiKey, apiBaseURL, model),
		model:   model,
		timeout: time.Duration(timeout) * time.Second,
	}
}

func (adapter *OpenAIImageAdapter) Generate(ctx context.Context, request GenerateImageRequest) (GeneratedImage, error) {
	if strings.TrimSpace(request.Prompt) == "" {
		return GeneratedImage{}, errors.New("image prompt is required")

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Re-fetch or regenerate the image — corrupt payloads from signed CDN URLs are often transient.
  2. If persistently failing, capture the bytes and run `file -k` / `identify` locally to confirm the header is well-formed.
  3. Verify the model's configured Size does not exceed 16384 on either dimension.
  4. If you control the source, ensure the encoder flushes the full file before returning.

Example fix

// before
data, err := downloadGeneratedImage(requestCtx, result.URL)
if err != nil { return GeneratedImage{}, err }
mimeType, extension, err := ValidateGeneratedImage(data)

// after (retry once on decode-class failures)
data, err := downloadGeneratedImage(requestCtx, result.URL)
if err != nil { return GeneratedImage{}, err }
if _, _, verr := ValidateGeneratedImage(data); verr != nil {
    logging.LogWarnf("generated image invalid, retrying once: %s", verr)
    data, err = downloadGeneratedImage(requestCtx, result.URL)
    if err != nil { return GeneratedImage{}, err }
}
mimeType, extension, err := ValidateGeneratedImage(data)
Defensive patterns

Strategy: retry

Validate before calling

// Cheap pre-check: decode config yourself first, with a clearer failure path
cfg, _, derr := image.DecodeConfig(bytes.NewReader(data))
if derr != nil {
    return fmt.Errorf("image header undecodable (truncated?): %s", derr)
}
if cfg.Width < 1 || cfg.Height < 1 || cfg.Width > 16384 || cfg.Height > 16384 ||
    int64(cfg.Width)*int64(cfg.Height) > 100_000_000 {
    return errors.New("image dimensions out of accepted range")
}

Try / catch

mimeType, ext, err := ValidateGeneratedImage(data)
if err != nil && err.Error() == "generated image is invalid" {
    // often transient (truncated download); retry once
    data, derr := downloadGeneratedImage(ctx, url)
    if derr == nil {
        mimeType, ext, err = ValidateGeneratedImage(data)
    }
}
if err != nil { return err }

Prevention

When it happens

Trigger: Bytes that pass mimetype detection but are truncated so image.DecodeConfig errors; a PNG/JPEG whose declared dimensions exceed 16384 on either side; a generated image whose total pixel count exceeds 100MP; a malformed header that the MIME sniffer accepted.

Common situations: Truncated download (connection dropped mid-body); provider returned a header-only stub; adversarial 'decompression bomb' style header; provider bug emitting a tiny valid header with no pixel data.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/d529f35f294a6d27. Report an issue: GitHub.