Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012uM7Ru1JYn48n6c5Rzwd99
97 lines
5.1 KiB
Markdown
97 lines
5.1 KiB
Markdown
# BUGS
|
||
|
||
## Open
|
||
|
||
### RM Styles: Random mode "picks the same styles over and over"
|
||
**Reported:** 2026-08-20
|
||
**Nodes:** RM Styles Full, RM Styles Full (Display), RM Styles Pipe
|
||
**Status:** Investigated — original hypothesis (number rounding) NOT confirmed. Two real
|
||
issues found, neither is the rounding.
|
||
|
||
**Original hypothesis:** the random prompt number is being rounded/manipulated into a
|
||
narrow range. **Disproved.** There is no float math anywhere in the path.
|
||
`_get_random_prompt()` uses `random.choice()` over a list of integer keys; the JS side
|
||
(`js/rm_styles_full.js`) does no random math at all in Random mode.
|
||
|
||
**Evidence — measured, not reasoned.** 602 real Random picks parsed out of
|
||
`user/comfyui*.log`, compared against 600 simulated runs of the node's own algorithm:
|
||
|
||
| metric | observed | simulated (correct picker) |
|
||
|---|---|---|
|
||
| max times any style picked (range 1–331, 321 draws) | 4 | 4 |
|
||
| styles never picked | 77 | 86 |
|
||
| per-style count variance | 0.781 | 0.891 |
|
||
| min gap between repeats | 31 | 31 (= history size + 1) |
|
||
|
||
Observed variance is slightly *below* random, i.e. the 30-item anti-repeat history is
|
||
working and the spread is marginally more even than chance. **The picker is statistically
|
||
sound.** Chart: `C:\Users\rober\Playground\style-frequency.html`
|
||
|
||
**Real issue 1 — `minimum`/`maximum` widgets silently shrink the library.**
|
||
`candidates = [n for n in available_numbers if minimum <= n <= maximum]`
|
||
(`nodes/styles_full.py:65`). Recent sessions ran `minimum=150, maximum=330`, which makes
|
||
**133 of 293 styles unreachable**. This is the actual cause of the perceived repetition —
|
||
the pool really is smaller, the picker is just faithfully sampling it. Also note style
|
||
`#999` is an outlier in `data/styles.json`; any `maximum` below 999 excludes it, and the
|
||
next-highest real style is 331.
|
||
|
||
**Real issue 2 (latent landmine) — the picker uses the *global* `random` module.**
|
||
`random.choice()` at `nodes/styles_full.py:76` shares Python's process-wide RNG. Many
|
||
ComfyUI packs call `random.seed(seed)` while they run (ComfyUI-Easy-Use's seed/wildcard
|
||
nodes, comfyui-frame-interpolation, ComfyUI-Hunyuan3DWrapper, basic_data_handling —
|
||
Easy-Use's own `py/server.py:5` carries a comment acknowledging this). If any such node
|
||
reseeds with a **fixed** seed before the styles node executes, `random.choice()` returns
|
||
the same index every run and the anti-repeat history turns the picker into a closed
|
||
deterministic cycle of exactly `RANDOM_HISTORY_SIZE + 1 = 31` styles. Reproduced:
|
||
|
||
```
|
||
distinct styles seen in 200 runs: 31
|
||
cycle: [232,233,234,235,236,237,238,240,...,268, 232,233,234,235,...] # repeats forever
|
||
```
|
||
|
||
That is *precisely* the reported symptom. It is not currently firing in the saved
|
||
workflows (none of them contain a reseeding node upstream), but it is one node away.
|
||
**Fix:** give the picker its own RNG — `_RNG = random.Random()` at module level, then
|
||
`_RNG.choice(...)` / `_RNG.randint(...)`. Immune to anything another pack does.
|
||
|
||
**Real issue 3 (minor) — "closest match" fallback silently reuses styles.**
|
||
`nodes/styles_full.py:245-248` snaps an unknown number to the nearest existing style. The
|
||
numbering has ~30 gaps (e.g. 42, 45, 48, 53 missing; nothing between 332 and 998), so in
|
||
Manual/Increment/Decrement modes a number landing in a gap silently repeats a neighbouring
|
||
style instead of erroring or skipping. Does not affect Random mode, where the number is
|
||
always drawn from existing keys.
|
||
|
||
## Resolved
|
||
|
||
### RM Styles: custom_json_path ignores quoted / relative / variable paths
|
||
**Reported:** 2026-08-07
|
||
**Nodes:** RM Styles Full, RM Styles Full (Display), RM Styles Pipe, Styles Editor modal
|
||
|
||
**Symptom:** Setting `custom_json_path` on an RM Styles node silently fell back to the
|
||
bundled `data/styles.json`, or logged `Styles file not found` for a file that exists.
|
||
|
||
**Evidence** (`user/comfyui.log`, 2026-08-07 09:40–09:43):
|
||
```
|
||
[RMStylesFull] Styles file not found: "C:\Users\rober\Documents\ComfyUI\ComfyUI\styles\Styles.csv"
|
||
```
|
||
The surrounding double quotes are part of the widget value — the log f-string adds none.
|
||
That file exists on disk.
|
||
|
||
**Root cause:** The path string from the free-text widget was passed straight to `Path()`.
|
||
`custom_json_path.strip()` removes whitespace only, so:
|
||
- Windows Explorer "Copy as path" quotes (`"C:\..."`) became part of the filename
|
||
- `~` and `%USERPROFILE%` were never expanded
|
||
- Relative paths resolved against ComfyUI's process CWD, not a predictable root
|
||
|
||
The node loader (`_load_styles`) and the editor API (`_resolve_styles_file`) each did their
|
||
own ad-hoc resolution, so they could also disagree about which file was being targeted.
|
||
|
||
**Fix:** Single shared `_normalize_styles_path()` in `nodes/styles_full.py`, used by both the
|
||
node loader and every editor API route. It strips whitespace, strips matched surrounding
|
||
quotes, expands `~` and environment variables, and resolves relative paths against the
|
||
ComfyUI base directory. Load failures now log the raw widget value alongside the resolved
|
||
path so a mismatch is visible.
|
||
|
||
**Note:** `.csv` styles files are still unsupported — the loader is JSON-only. A CSV path
|
||
now resolves correctly but fails at parse time with an explicit message.
|