X-WIDE Latent Receiver 潜空间接收器
The latent that came out of a PNG's EXIF
- latent
The node is trivial - one dropdown, one output, one number - but the file it reads is odd: a latent that arrived as a picture, stuffed into a PNG's metadata block. That explains everything about how it behaves, including why it sometimes hands you an empty latent with a shrug.
What it is
XWIDE_LatentReceiver is the receiving half of the X-WIDE latent pair, a standalone re-wrap of ltdrdata's Impact Pack Latent Receiver (GPL-3.0, no Impact Pack needed, protocol-compatible with the original). You reach for it when a graph needs a latent produced somewhere else - a feedback loop, a pipeline split across the canvas, or a second workflow tab on the same machine.
The payoff over the image pair is skipping a VAE decode and encode. Both are lossy, and workflows that repeatedly round-trip through the VAE accumulate that damage - passing the tensor keeps the second half of the pipeline working on exactly what the first half produced.
How it works
The sender writes temp/latents/<name>_00001_.latent.png: a Latent2RGB preview with the safetensors-serialized latent zipped into the PNG's EXIF UserComment, and fires a latent-send event. Every receiver whose link_id matches gets that filename written into its latent dropdown as an annotated path - latents/LatentSender_00001_.latent.png [temp] - plus a preview on the node. The bracket is the important part: [temp] tells the backend to look in the scratch folder rather than input/.
On execution it reads that path and reconstructs the tensor. For a .latent.png it opens the image, pulls the EXIF block with piexif, reads the zipped latent entry, and safetensors loads it back into a proper {"samples": ...} dict. For a plain .latent it loads the safetensors file directly - and if that file lacks the latent_format_version_0 marker (an old-style file holding an unscaled latent) it applies the same 1/0.18215 multiplier ComfyUI's LoadLatent uses, so you never get a doubled or halved latent. This pack's own files always carry the marker, so nothing gets scaled twice.
IS_CHANGED here is better than the image receiver's: it SHA-256s the file's bytes rather than hashing the filename, so a genuinely different latent re-triggers execution. trigger_always overrides it with the classic always-dirty NaN return.
Inputs and outputs
latent- the file picker, auto-filled by the sender. It also lists.latentand.latent.pngfiles fromComfyUI/input/, so you can point it at one you stashed there yourself.link_id- pairing number, default0, must match the sender.trigger_always-falseby default; force a re-run each queue.
The single output is latent (LATENT). Wire it into KSampler's latent_image, a VAEDecode, a latent upscaler, whatever comes next - anything taking a normal LATENT will accept it, because that's what it is. No custom type for downstream nodes to learn.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/XWIDE/comfyui-x-wide-image-latent-sender-receiver
Restart, then Ctrl + F5 - the latent-send listener is front-end JavaScript, so a cached page means the node never updates. Manager users can search X-WIDE Image Latent Sender / Receiver. Zero downloads, zero pip install: the dependency list is empty, and it leans on libraries ComfyUI already ships (piexif, safetensors, torch/numpy/Pillow). The GitHub repo was renamed in October 2026; the shorter legacy URL redirects, so both clone commands work.
Where people get burned
You get a tiny blurry result. That's the fallback, not a model problem: when the file can't be found or read, the node logs a warning and outputs an empty latent, shape 1×4×8×8, which decodes to a 64×64 image. Since temp/ is cleared on restart, an old workflow reopened the next day is exactly this case. Re-run the sender once.
It used to red-box instead of degrading. In the original, a missing latent file was rejected at validation, so a wall of reopened workflows turned red after a restart. This version only rejects absolute paths and .. traversal, downgrading a missing file to a warning - and fixes a subtle bug where an unconnected receiver returned a bare tensor instead of a {"samples": ...} dict, breaking downstream nodes with a confusing type error.
Reaching for it when you don't need it. If both halves of your graph are already joined by a visible wire, skip this pair. It's for crossing a gap the graph can't express - reuse across runs, or a handoff between tabs - and it hands off between runs: the receiver reads the filename it held at queue time, so a send lands on the next execution.
Sharing the latent with someone. Hand over the .latent.png; they can load it with this node or the original. Don't convert or screenshot it - the tensor lives in the EXIF block, and re-encoding throws it away like any other metadata.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | COMBO | 要读取的 latent 文件(.latent 或带预览的 .latent.png)。收到 Sender 发来的文件后这里会自动填入。 / Latent file to load (.latent, or a preview .latent.png). Filled automatically with the received file. | |
| link_id | INT | 00–9223372036854776000 | 配对编号:和 Latent Sender 的 link_id 相同才会收到它的 latent。 / Pairing id: only the Sender with the same link_id will send to this node. |
| trigger_always | BOOLEAN | false | 开启后本节点每次都重新执行(忽略缓存)。 / When enabled the node always re-executes, ignoring the cache. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |