jeecgboot/JeecgBoot · error · IOException

生成验证码base64失败

Error message

生成验证码base64失败

What it means

Thrown by RandImageUtil.generate(String) — the base64 overload — when ImageIO.write fails to encode the BufferedImage into a ByteArrayOutputStream, or when Base64 encoding fails. Like error 267, createVerifyCodeImage has its own fallback (createErrorImage), so the root cause is usually in ImageIO.write or ByteArrayOutputStream operations. This variant returns a data URI string (data:image/jpg;base64,...) and is typically used by frontends that render the captcha from base64.

Source

Thrown at jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/util/RandImageUtil.java:102

     */
    public static String generate(String verifyCode) throws IOException {
        if (verifyCode == null || verifyCode.trim().isEmpty()) {
            throw new IllegalArgumentException("验证码不能为空");
        }
        
        try {
            BufferedImage image = createVerifyCodeImage(verifyCode);
            
            try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
                ImageIO.write(image, IMG_FORMAT, byteStream);
                byte[] bytes = byteStream.toByteArray();
                String base64 = Base64.getEncoder().encodeToString(bytes).trim();
                // 清理换行符
                base64 = base64.replaceAll("[\r\n]", "");
                return BASE64_PREFIX + base64;
            }
        } catch (Exception e) {
            throw new IOException("生成验证码base64失败", e);
        }
    }

    /**
     * 创建验证码图像
     * 
     * @param verifyCode 验证码字符串
     * @return 验证码图像
     */
    private static BufferedImage createVerifyCodeImage(String verifyCode) {
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = null;
        
        try {
            graphics = (Graphics2D) image.getGraphics();
            
            // 设置图形渲染质量
            setupRenderingHints(graphics);

View on GitHub (pinned to 96fb33f5ec)

Solutions

  1. Install font and image libraries in the container: apt-get install -y fontconfig fonts-dejavu-core libjpeg62-turbo (Debian) or apk add fontconfig ttf-dejavu libjpeg-turbo (Alpine).
  2. Verify the JDK has the JPEG ImageIO plugin: run ImageIO.getWriterFormatNames() in a test — it should include 'JPEG' or 'jpg'.
  3. If using a stripped JRE, switch to a full JDK or add the javax.imageio JPEG plugin dependency (com.twelvemonkeys.imageio:imageio-jpeg).
  4. Reduce INTERFERENCE_LINE_COUNT (currently 200) if memory is tight, or increase JVM heap (-Xmx).
  5. Wrap the call site in try-catch and return a fallback captcha mechanism (e.g., text-based math captcha) if image generation is unavailable.

Example fix

// before: unhandled IOException at call site
String base64Captcha = RandImageUtil.generate(verifyCode);
return Result.OK(base64Captcha);

// after: graceful fallback on image generation failure
try {
    String base64Captcha = RandImageUtil.generate(verifyCode);
    return Result.OK(base64Captcha);
} catch (IOException e) {
    log.error("验证码图片生成失败,使用备用方案", e);
    return Result.OK("data:image/png;base64," + generateFallbackTextCaptcha(verifyCode));
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate environment can produce images before relying on base64 captcha
public boolean isImageIOWAvailable() {
    try {
        BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        boolean canWrite = ImageIO.write(img, "JPEG", baos);
        return canWrite;
    } catch (Exception e) {
        return false;
    }
}

Try / catch

try {
    String base64 = RandImageUtil.generate(verifyCode);
    return Result.OK(base64);
} catch (IOException e) {
    log.error("Base64 captcha generation failed", e);
    // Fallback: return a simple text-based challenge
    return Result.OK("VERIFY:" + verifyCode);
}

Prevention

When it happens

Trigger: Headless environment where JPEG codec is unavailable or misconfigured. BufferedImage creation fails silently and createErrorImage also encounters an issue. Extremely low memory causing ByteArrayOutputStream or Base64 encoder to throw OutOfMemoryError (which extends Error, not Exception, so it would propagate differently — but the catch block catches Exception). Corrupted AWT/GraphicsEnvironment on the JVM.

Common situations: Minimal Docker images without libfontconfig or JPEG native libraries. JDK distribution that lacks the JPEG ImageIO plugin (some compact profiles or JRE strips). Server running with very tight heap limits where 200 interference lines + image buffer exhaust memory under load.

Related errors


AI-assisted analysis of jeecgboot/JeecgBoot@96fb33f5ec (2026-08-14). Data as JSON: /api/errors/2fda75232eb20afd. Report an issue: GitHub.