SDXL Dual CLIP Encode
The reason this pack exists
- clip
- cond_positive
- cond_negative
This is the node the whole SDXL Adherence pack is built around. SDXL's CLIP silently splits long prompts into 75-token chunks - you don't get a warning, you just get a subject that drifts and a prompt where the important words landed in the wrong chunk. On top of that, SDXL conditioning needs a pooled output for its ADM timestep embedding, and when that's missing you get the classic NoneType pooled_output crash. SDXL Dual CLIP Encode addresses both: it encodes positive and negative conditioning in one node, guarantees pooled_output on every entry, and splits your prompt into early/late/essentials that it weights and time-schedules so the subject stays front and center.
If you use one node from this pack, it's this one. The README is blunt about it - "NoneType pooled_output or ADM crash: always run conditioning through SDXL Dual CLIP Encode from this pack."
How it works
You get four text inputs with distinct jobs: early_text is your subject and key attributes (this is what gets protected), late_text is aesthetics and long-tail detail, neg_text is the negative, and essentials_text is a short list of keywords to softly reinforce. Internally it tokenizes with clip.tokenize and encodes with clip.encode_from_tokens(..., return_pooled=True), so pooled output is never missing.
The clever part is what happens after. In auto mode (default), prompts under ~112 tokens take a straightforward path: early text at full weight, late text blended by early_late_mix (default 0.4), essentials locked by essentials_lock (default 0.35). At or above 112 tokens it switches to a fused single encode plus soft, time-ramped "head" and "tail" echoes - a few tokens from the start of the prompt get a gentle early weight that fades out, and tail tokens fade in late, each entry carrying timestep_start/timestep_end so the sampler applies them at the right phase. Essentials get the same treatment, kept early-only and skipped entirely on very long prompts so they can't over-constrain.
The scheduler-aware tweaks are worth wiring up: feed your KSampler's steps into total_steps and cfg into the cfg input, and the node adapts its ramp timing and caps the extra weight at high CFG so the guidance doesn't flip late in the run. width/height trigger resolution-aware bumps above 1280px. And mode lets you opt out: core_parity behaves like the stock ComfyUI encoder (one fused entry, no assists), while custom_only gives you the early/late/essentials blending without the long-prompt machinery.
clip_skip_openclip (default 1) and clip_skip_clipL (default 0) are CLIP skip per-encoder. Leave them alone unless you know why you're changing them.
Outputs
Two CONDITIONING outputs: cond_positive and cond_negative, straight into the KSampler. In the pack's quick-start you'd normally drive them from the SDXL Prompt Styler's four text outputs, but the encoder works fine as a standalone with your own text.
Installing it
One pack, one install, all nodes included:
cd ComfyUI/custom_nodes
git clone https://github.com/regiellis/ComfyUI-SDXL-Adherence
Restart ComfyUI, or search "SDXL Adherence" in ComfyUI Manager. No model downloads, no extra dependencies.
Troubleshooting - the mid-run flip
The README's big warning: if the KSampler preview changes drastically partway through, that's usually a conditioning-schedule problem, not a sampler problem. The checklist, in order:
- Switch
mode. Long prompt →core_paritymatches core exactly. Short/medium →custom_onlyif you want the blending without assists. - Pass sampler context. Wire KSampler
steps→total_stepsandcfg→cfgso the ramps adapt instead of guessing. - Keep guidance moderate. CFG ~5.5–7.0, CFG rescale ~0.7–0.8. Extreme rescale is a known late-flip trigger, and the node will literally print a hint about it if you feed it the value.
- Stabilize the canvas. Stick to 64-safe sizes (1536×896, not 1500×900), don't stack heavy LoRAs, and test with other conditioning nodes disabled to isolate the cause.
- Empty
essentials_texton very long prompts. Essentials are time-limited to early steps already, but redundant terms still over-constrain.
If you want to see what it's actually doing, run ComfyUI with ADHERENCE_DEBUG=1 and each encode prints a one-line summary of tokens, caps, and ramp slices. That single line has saved more than one debugging session.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| clip | CLIP | SDXL CLIP from CheckpointLoader (dual encoders). | |
| early_text | STRING | Primary prompt (subject, key attributes). | |
| late_text | STRING | Aesthetics / long-tail details. | |
| neg_text | STRING | Negative prompt. | |
| essentials_text | STRING | Keywords to softly reinforce. | |
| early_late_mix | FLOAT | 0.400–1 | Blend for late_text in custom/short mode. |
| essentials_lock | FLOAT | 0.350–1 | Extra weight for essentials in custom/short mode. |
| clip_skip_openclip | INT | 10–2 | OpenCLIP skip (global). |
| clip_skip_clipL | INT | 00–2 | CLIP-L skip (local). |
| mode | COMBO | auto | auto=fused + soft head/tail ramps on long prompts; core_parity=single fused entry; custom_only=early/late/essentials blending. |
| widthopt | INT | 102464–8192 | For res-aware heuristics (optional). |
| heightopt | INT | 102464–8192 | For res-aware heuristics (optional). |
| total_stepsopt | INT | 00–200 | Optional: sampler total steps for adaptive ramps. |
| cfgopt | FLOAT | 0.000–30 | Optional: CFG for adaptive cap. |
| cfg_rescaleopt | FLOAT | 0.000–2 | Optional: warn if extreme (can cause late flips). |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| cond_positive | CONDITIONING | — |
| cond_negative | CONDITIONING | — |