Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012uM7Ru1JYn48n6c5Rzwd99
5.1 KiB
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.