H3RelayEditAppend
The node that stitches your character swap back together
- frames
- audio
- previous
- H3_REMOVAL_STATE
- IMAGE
- AUDIO
If you found this page because ComfyUI threw an error on H3RelayEditAppend, you are looking at a node you didn't place. It's internal plumbing, generated automatically when H3 Relay Windowed Edit · Character Swap expands into a real graph. You can read it, inspect it, even patch a wire - but you don't build a workflow out of it.
That said, it's the node where the whole trick lives or dies, so it's worth understanding.
What it actually does
H3 Relay runs long edits as a chain of separate windows, because MiniMax H3 was trained on 4–15 second clips and there's no honest way around that. Each window comes back from the sampler as a freshly decoded batch of frames plus a fresh audio waveform, on its own little clock, with a chunk of deliberately repeated material at the front.
H3RelayEditAppend is the join. It takes one window's output, cuts it to the part that's genuinely new, splices it onto everything the earlier windows already produced, and hands the growing assembly back down the chain as a single state object.
Three things it's fussy about, all for good reasons:
- It expects exactly the window length you configured. One frame short and it logs a warning and holds the final frame (the known H3 VAE decode quirk); longer and it refuses outright.
- It rebuilds the audio against 24 fps source time, not the model's internal length. Audio is sliced by sample offset from
start, and if the waveform no longer lines up with the source clock the node raises rather than quietly desyncing your clip. - The retained boundary frame at
startis dropped from delivery. It was there so the model had a clean seam to continue from, not so you'd watch it twice.
Inputs and outputs that matter
The required inputs are frames, audio, start, source_count and window_frames. In practice all five are wired by the parent node - start is the source-frame index this window begins at, source_count is the length of the original clip, window_frames is the H3 grid size for this window (22, 39, 56 … 362, i.e. 17n+5).
The optional ones are the interesting part, and they exist for caching rather than for you:
previous- the runningH3_REMOVAL_STATEfrom the window before. Leave it empty and this window is treated as the start of the sequence.cache_scope,config_key,window_index,window_seed- identity for the disk checkpoint system.cache_scopebinds a checkpoint to this workflow and node;config_keyis a hash of the actual pixels, prompt and model graph. When both are set, the node writes the exact float frames to disk so a later run can skip the sampler entirely.reuse_record- tells the node this window is a restore, not a fresh render, so it validates against the saved record instead of writing a new one.preview_runandwindow_index- where to publish the hover-to-play preview card.window_metadata- the window-plan entry (source range, target size, history, padding) serialised as JSON.
Outputs: the updated H3_REMOVAL_STATE, plus IMAGE and AUDIO for the assembled prefix so far. The final window's IMAGE/AUDIO pair is what eventually reaches Save Video or Create Video.
Install
Nothing here installs separately - it ships with the pack:
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/akatz-ai/h3-relay.git
or search H3 Relay in ComfyUI Manager and restart. The pack needs ComfyUI 0.32.0 or newer, FFmpeg on PATH, and the MiniMax H3 weights listed in its MODELS.md; there are no pip dependencies to fight with, which is genuinely rare for a 2026 video pack. The character image, source video and both VAEs are wired on the parent node, not here.
When it complains
Expected N decoded frames, received M- the window size on this append node doesn't match thewindow_framesthe parent planned. If you edited the graph by hand, you changed one and not the other.Generated audio no longer matches the source clock- almost always astart/source_countmismatch, or a source clip whose frame rate is not 24. Resample first.Saved window history does not match this render- the checkpoint record'sconfig_keyor its recorded predecessor chain disagrees with the current graph. Something upstream changed: pixels, prompt, steps, or a model file. Re-rendering the window onwards is the sanctioned fix; see H3RelayRemovalRestore for what the cache is actually enforcing.Invalid source-aligned overlap- the previous state ends before this window starts, or overlaps by more than a whole window. That's a graph-shape problem, not a settings problem.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| frames | IMAGE | — | |
| audio | AUDIO | — | |
| start | INT | — | |
| source_count | INT | — | |
| window_frames | INT | — | |
| previousopt | H3_REMOVAL_STATE | — | |
| preview_runopt | STRING | — | |
| window_indexopt | INT | 0 | — |
| cache_scopeopt | STRING | — | |
| config_keyopt | STRING | — | |
| window_seedopt | STRING | 0 | — |
| reuse_recordopt | STRING | — | |
| window_metadataopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| H3_REMOVAL_STATE | H3_REMOVAL_STATE | — |
| IMAGE | IMAGE | — |
| AUDIO | AUDIO | — |