You finish an SDXL render or an inpaint composite and the output has blocky 8x8 JPEG artifacts at high-contrast edges, visible banding in gradients (especially sky and skin), and color quantization in shadow areas. It looks fine in the live preview at 50% zoom, but at 100% it falls apart. Two distinct causes usually combine: the VAE decode introducing fp16 bit-depth errors (the SDXL default VAE is notorious for this) and a lossy JPEG export quantizing the already-fragile output a second time.
Fastest fix: swap to the madebyollin/sdxl-vae-fp16-fix VAE, and export your final image as PNG instead of JPEG. That kills both causes at once. Those two changes solve the large majority of cases; the rest of this guide is for when artifacts survive that, when JPEG is mandatory, or when the seam follows an inpaint mask.
Which bucket are you in
Find your symptom in the left column, confirm the tell, then jump to the matching step.
| Symptom you see | The tell that confirms it | Real cause | Go to |
|---|---|---|---|
| Banding in skies/skin, color “holes”, only on SDXL | SD 1.5 with the same workflow is clean | fp16 VAE NaN bug | Step 1 |
| 8x8 grid on every sharp edge | Visible at 100% zoom, regular square pattern | JPEG quality 80 or below | Step 2 |
| Only red/blue edges smear; green/white stay sharp | Lipstick, neon, sunsets fuzz and shift | 4:2:0 chroma subsampling | Step 3 |
| Artifacts that were not in the source | Native res was clean, upscale introduced them | Upscaling a lossy input | Step 4 |
| Seam tracing the exact shape of your mask | Outline matches your inpaint selection | Inpaint denoise/mask mismatch | Step 5 |
If two rows match, fix top-down. Step 1 and Step 2 together resolve most reports.
Shortest path to fix
Step 1: Swap the SDXL VAE
The original SDXL VAE overflows in fp16 because its internal activations are too large; on fp16 GPUs that produces NaN pixels, which surface as banding, color holes, and edge garbage. The community fix is madebyollin/sdxl-vae-fp16-fix, a VAE finetuned to stay in range at fp16. It is based on SDXL-VAE 0.9 but works with SDXL 1.0, and as a bonus it decodes faster and uses less VRAM than running the VAE in fp32.
Download the file from Hugging Face (madebyollin/sdxl-vae-fp16-fix). The repo’s primary file is named sdxl.vae.safetensors; you can keep that name or rename it to something obvious like sdxl-vae-fp16-fix.safetensors. Place it in your tool’s VAE folder:
Automatic1111: stable-diffusion-webui/models/VAE/
ComfyUI: ComfyUI/models/vae/
Forge: webui/models/VAE/
Then select it explicitly instead of “Automatic” or the checkpoint’s “Baked VAE”:
- Automatic1111 / Forge: Settings > Stable Diffusion > “SD VAE” dropdown, pick the file. If it does not appear, click the refresh icon next to the dropdown (Forge and A1111 only scan the folder at startup).
- ComfyUI: add a
Load VAEnode, choose the file from the dropdown, and wire itsVAEoutput into yourVAEDecodenode so it overrides the checkpoint’s baked VAE. The dropdown only lists files inmodels/vae/, and filenames are case-sensitive. - Diffusers:
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16)and pass it to your pipeline.
Re-render the same prompt and seed. The banding and edge artifacts should disappear immediately.
If you cannot use the fp16-fix variant, fall back to decoding the VAE in fp32: add --no-half-vae to your Automatic1111 / Forge launch flags. Slower and uses more VRAM, but stable.
Step 2: Export to PNG, not JPEG
For final delivery and anything where quality matters, use a lossless format. PNG never produces JPEG block artifacts:
Automatic1111: Settings > Saving images/grids > "File format for images": png
ComfyUI: Save Image node (default output is PNG)
Photoshop: File > Export > Export As > PNG
Affinity: File > Export > PNG
File size runs roughly 3-5x a JPEG, but for a 1024x1024 image that is trivial. If you need a smaller lossless-quality file for the web in 2026, lossless WebP or near-lossless AVIF cut size further than PNG while still avoiding 8x8 blocks (see Step 3).
Step 3: When JPEG (or web upload) is unavoidable, set quality 95+ and disable chroma subsampling
If JPEG is required (file-size caps, email, a CMS that only accepts JPEG), the chroma subsampling switch matters more for color edges than the quality slider does. Standard JPEG uses 4:2:0 below quality 100, which stores color at half resolution and smears saturated red/blue edges. Force 4:4:4 (no subsampling):
Photoshop: File > Export > Save for Web (Legacy) > JPEG, Quality 95+, check "Progressive"
(Save for Web outputs 4:4:4 at quality 51 and above)
Affinity: Export > JPEG > Quality 95, set "Chroma subsampling" to None / 4:4:4
ImageMagick: magick input.png -quality 95 -sampling-factor 4:4:4 output.jpg
(older builds use the legacy command: convert input.png -quality 95 -sampling-factor 1x1 output.jpg)
Squoosh: MozJPEG, Quality 92-95, set "Chroma subsampling" to 4:4:4
Note: -sampling-factor 1x1 and 4:4:4 mean the same thing (no subsampling); newer ImageMagick 7 prefers the magick command and accepts the 4:4:4 form. For web targets where the platform allows it, exporting WebP (quality 90+) or AVIF avoids JPEG’s 8x8 blocking entirely at a smaller file size, which is the cleaner 2026 option than fighting JPEG quality settings.
Step 4: Render small, upscale large, deliver downscaled
Upscaling a lossy or low-detail input amplifies whatever artifacts it already has. Render clean at native resolution, upscale, then downscale to your delivery size so the final resample averages away leftover noise:
Render: 1024x1024 (lossless, in-memory)
Upscale: 4x with a grain-preserving model (e.g. 4x_NMKD-Siax) to 4096x4096
Downscale: Lanczos/area to your target (1920x1920 or 1080x1080)
Export: PNG, or JPEG quality 95 at 4:4:4
Never upscale a JPEG you already exported; upscale the lossless render or latent, not a recompressed file.
Step 5: Soften inpaint mask edges
If the artifact traces the exact outline of your inpaint selection, it is a denoise/mask seam, not JPEG. Widen the transition and lower denoise so the new region blends into surrounding texture:
Mask blur: 8 to 16 px (default is often 2-4)
Mask padding: 32 px
Inpaint denoise: ~0.4 (0.6+ over-changes and breaks the blend)
Inpaint area: "Whole picture" for blends, "Only masked" for surgical fixes
A wider mask blur spreads the denoise gradient over more pixels, hiding the seam.
How to confirm it’s fixed
- Open the final file at 100% (1:1) zoom, not the live preview.
- Inspect a gradient (sky, cheek, soft shadow): it should fade smoothly with no stair-step bands.
- Inspect a hard, saturated edge (lips, a neon sign, a bright sky/building boundary): no 8x8 grid, no color fringing or bleed.
- If you exported JPEG, reopen the saved file (not the editor canvas) and re-check, since the artifacts are introduced by the save, not what you see before it.
- Optional precision check: open the source PNG and the exported JPEG as layers, set the top to “Difference” blend mode, and boost levels. Bright square clusters along edges mean the JPEG settings still need work.
Prevention
- Make
sdxl-vae-fp16-fixyour default SDXL VAE; never trust the checkpoint’s baked one for SDXL. - Set Automatic1111 / Forge default save format to PNG; switch to JPEG only per-export.
- Never reupload an AI image through Twitter/X, Facebook, or WhatsApp if you care about quality. They recompress to roughly quality 70-80 with 4:2:0.
- For client deliveries, send both a PNG master and a JPEG quality-95 (or WebP) preview.
- Build the habit of zooming to 100% on the saved file before shipping.
FAQ
Is this a problem with my model or my GPU? Neither, really. The fp16 NaN issue is a property of the original SDXL VAE math overflowing at fp16; it shows up on most consumer GPUs running fp16. Swapping the VAE (Step 1) fixes it without changing your checkpoint or hardware.
The fp16-fix VAE made my colors look slightly different. Is that expected?
Yes. The fix is a finetune, so there are small differences from the original VAE output. They are minor and overwhelmingly better than NaN banding. If you need bit-exact original output, use --no-half-vae (fp32 decode) instead.
I exported PNG and still see banding. What now? Then it is not the export; it is Step 1 (VAE) or Step 5 (inpaint seam). PNG only rules out JPEG block artifacts. Re-render with the fp16-fix VAE and check at 100%.
Why does my image look fine in the editor but bad after I save the JPEG? JPEG artifacts are created at the moment of compression. The editor shows you the uncompressed canvas; the damage appears only in the written file. Always re-open the saved file to judge it.
Should I just use WebP or AVIF instead of fighting JPEG? If your target platform accepts them, yes. As of June 2026 both avoid 8x8 blocking and give smaller files than a quality-95 4:4:4 JPEG. Keep a PNG master regardless.
Does upscaling fix existing JPEG artifacts? No. Upscaling amplifies them. Fix the source first (Steps 1-3), then upscale the clean render, then downscale to delivery size (Step 4).
Related
- AI Image Photo Grain Missing
- AI Image Low Detail
- AI Image Background Bleed onto Subject
- AI Image Overprocessed CG
- AI Image Skin Too Smooth and Plastic
- AI Image Watermark Residue
- AI Image Text Wrong Language
External references: