Skip to content

Fix RegexExtract crashing/returning None on non-participating capture groups#15031

Open
vidigoat wants to merge 1 commit into
Comfy-Org:masterfrom
vidigoat:fix/regex-extract-non-participating-group
Open

Fix RegexExtract crashing/returning None on non-participating capture groups#15031
vidigoat wants to merge 1 commit into
Comfy-Org:masterfrom
vidigoat:fix/regex-extract-non-participating-group

Conversation

@vidigoat

Copy link
Copy Markdown
Contributor

Problem

The RegexExtract node (Extract Text) crashes or leaks a non-string value when a requested capture group didn't participate in the match.

In "First Group" and "All Groups" modes the code only checks len(match.groups()) >= group_index, then calls match.group(group_index). When the group is optional or on a non-taken alternation branch, match.group() returns None:

# "First Group"
re.search(r"(\d+)-(\d+)|(\w+)", "hello")   # matches via the (\w+) branch
match.group(1)                              # -> None  (returned from a String output)

# "All Groups"
# appends None, then join() raises:
# TypeError: sequence item 0: expected str instance, NoneType found  (workflow aborts)

So a common pattern with an alternation or optional group either silently sends None into string-consuming nodes ("First Group") or hard-crashes prompt execution ("All Groups").

Fix

Guard both branches with is not None, so a non-participating group yields "" (matching the node's existing "no match" behaviour). Normal matches are unchanged.

Added tests-unit/comfy_extras_test/nodes_string_test.py covering both modes with non-participating groups plus the normal paths; it fails before this change (None return + TypeError) and passes after. The full test runs green against the real node.


Disclosure: I used an AI assistant while working on this; I reproduced the bug, wrote the fix and test, and verified everything myself.

In the 'First Group' and 'All Groups' modes, RegexExtract called
match.group(group_index) after only checking len(match.groups()), without
checking that the group actually participated in the match. When the
requested group is optional or on a non-taken alternation branch,
match.group() is None:

- 'First Group' returned None from a node whose output is a String, leaking
  a non-string value into downstream string nodes.
- 'All Groups' appended None and then crashed in join() with an uncaught
  TypeError, aborting the workflow.

Guard both branches with 'is not None' so a non-participating group yields
an empty string. Normal matches are unaffected. Adds a regression test.
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 38648301-cbc2-443f-9568-f23d1c83dcfb

📥 Commits

Reviewing files that changed from the base of the PR and between 54ca919 and 067cb8c.

📒 Files selected for processing (2)
  • comfy_extras/nodes_string.py
  • tests-unit/comfy_extras_test/nodes_string_test.py
📜 Recent review details
⏰ Context from checks skipped due to timeout. (8)
  • GitHub Check: test (windows-2022)
  • GitHub Check: test (macos-latest)
  • GitHub Check: test (ubuntu-latest)
  • GitHub Check: test
  • GitHub Check: test (windows-latest)
  • GitHub Check: Run Pylint
  • GitHub Check: test (macos-latest)
  • GitHub Check: test (ubuntu-latest)
⚠️ CI failures not shown inline (2)

GitHub Actions: CLA Assistant / 0_cla-assistant.txt: Fix RegexExtract crashing/returning None on non-participating capture groups

Conclusion: failure

View job details

##[group]Run contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08
 with:
   path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
   remote-organization-name: comfy-org
   remote-repository-name: comfy-cla
   path-to-signatures: signatures/cla.json
   branch: main
   allowlist: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
   custom-notsigned-prcomment: 🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
   custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
   custom-allsigned-prcomment: ✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
   use-dco-flag: false
   lock-pullrequest-aftermerge: true
   suggest-recheck: true
 env:
   GITHUB_***REDACTED***
   PERSONAL_ACCESS_***REDACTED***
 ##[endgroup]
 CLA Assistant GitHub Action bot has started the process
 (node:2087) [DEP0040] DeprecationWarning: The `punycode` module is deprec...

GitHub Actions: CLA Assistant / cla-assistant: Fix RegexExtract crashing/returning None on non-participating capture groups

Conclusion: failure

View job details

##[group]Run contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08
 with:
   path-to-document: https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md
   remote-organization-name: comfy-org
   remote-repository-name: comfy-cla
   path-to-signatures: signatures/cla.json
   branch: main
   allowlist: action@github.com,actions-user,ampagent,claude,comfy-pr-bot,GitHub Action,github-actions,github-actions[bot],Glary Bot,Glary-Bot,*[bot]
   custom-notsigned-prcomment: 🎉 Thank you for your contribution, we really appreciate it! 🎉
Like many open source projects, we require contributors to sign our [Contributor License Agreement (CLA)](https://github.com/Comfy-Org/comfy-cla/blob/main/comfyui_icla.md). A CLA makes the ownership of contributions explicit, so contributors and the project share a clear understanding of how the code can be used. By signing, you:
- Confirm that you own your contribution.
- Keep the right to reuse your own code.
- Grant us a copyright license to include and share it within our projects.
CLAs are standard practice across major open source projects including those under the Apache Software Foundation and the Linux Foundation. Ours is based on the Apache Software Foundation's CLA. Most importantly, it would enable us to relicense the project under a more permissive license in the future, giving the project and its community greater flexibility.
✍ **To sign, please post a new comment on this PR with exactly the following text:** ✍
   custom-pr-sign-comment: I have read and agree to the Contributor License Agreement
   custom-allsigned-prcomment: ✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
   use-dco-flag: false
   lock-pullrequest-aftermerge: true
   suggest-recheck: true
 env:
   GITHUB_***REDACTED***
   PERSONAL_ACCESS_***REDACTED***
 ##[endgroup]
 CLA Assistant GitHub Action bot has started the process
 (node:2087) [DEP0040] DeprecationWarning: The `punycode` module is deprec...
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

**/*: Keep changes small, direct, and limited to the narrowest code path and fewest files necessary; prefer practical fixes over broad architectural work.
Prefer fewer dependencies and do not add a ComfyUI dependency unless absolutely necessary.
Remove obsolete code, dead branches, unused options, debug prints, and unnecessary compatibility paths.
Preserve existing APIs, node names, model-loading behavior, file layout, and workflow compatibility unless replacement is explicit.
Keep architectural layers focused; do not leak UI, API, workflow, queue, persistence, telemetry, model-loading, node, or execution concerns into unrelated layers.
Shared core modules should depend only on lower-level primitives and their own domain concepts; higher-level concepts belong at callers, adapters, services, or boundaries.
Pass only the narrowest data needed across boundaries and keep identity mapping, persistence, history, telemetry, response shaping, and UI state in their owning layers.
Before touching many files, identify the smallest owner layer; use caller-side mappings, adapters, events, or narrow interfaces instead of exposing private concepts across layers.
Core ComfyUI code must not make unsolicited internet requests or add uploads, telemetry, analytics, tracking, reporting, update checks, remote configuration, licensing checks, or similar outbound paths.
Model downloading is allowed only when explicitly authorized by the user, limited to the requested artifact, and free of telemetry, tracking, unrelated metadata, or background activity.
Warning and info messages should be short and actionable; documentation and README changes should be concise, factual, and tied to changed behavior.
Use short direct commit subjects such as Fix ..., Add ..., Support ..., Remove ..., or Update ...; keep PR descriptions short and state the problem, behavior change, and tests.
Prefer one coherent behavioral change per commit and prioritize crashes, incorrect dtype/device behavior, m...

Files:

  • tests-unit/comfy_extras_test/nodes_string_test.py
  • comfy_extras/nodes_string.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Keep state and capability flags on the object that owns the behavior; use explicit parent-owned fields rather than probing children with getattr for parent control flow.
Keep public methods aligned with caller contracts; preserve arguments, parameter order, return types, side effects, and error behavior unless all affected interfaces are intentionally updated.
Do not add unused compatibility parameters, flags, attributes, constructor options, or model-specific options to shared helpers.
Normalize third-party and upstream return conventions at integration boundaries so core code receives the expected type and shape.
Avoid caller-side unwrapping such as out = out[0] unless the called interface documents that return structure.
Do not add torch.no_grad, torch.inference_mode, or inference-mode wrappers; only disable a globally enabled inference mode when a training path requires gradients.
Do not add freeze, unfreeze, or trainability toggles to ComfyUI model classes.
Remove training-only behavior such as dropout from inference models while preserving checkpoint and state-dict compatibility, using nn.Identity when necessary to retain slots.
Keep imports at module scope; use inline imports only for established optional-backend probes or import-cycle avoidance.
Use try/except only for optional dependency, platform, or backend detection with a useful fallback, and prefer specific exception types.
Do not add code for unsupported pinned library versions or obsolete PyTorch workarounds; unsupported formats, quantization metadata, and bad states should fail clearly.
Match local file style and keep comments sparse, useful, and non-obvious; remove comments that merely restate code.

Files:

  • tests-unit/comfy_extras_test/nodes_string_test.py
  • comfy_extras/nodes_string.py
**

⚙️ CodeRabbit configuration file

**: IMPORTANT: Only comment on issues directly introduced by this PR's code changes.
Treat AGENTS.md as mandatory repository policy, not optional style guidance.
Flag PR changes that violate AGENTS.md even when the code is otherwise functional.
In particular, enforce architecture boundaries, dtype/device/memory rules,
interface contracts, import style, no unnecessary try/except blocks, no inline
imports, no outbound internet paths in core ComfyUI, and narrow scoped fixes.
Prefer direct findings over suggestions when a rule is violated. Only ignore
AGENTS.md when it clearly conflicts with a newer explicit maintainer instruction
in the PR.
Do NOT flag pre-existing issues in code that was merely moved, re-indented,
de-indented, or reformatted without logic changes. If code appears in the diff
only due to whitespace or structural reformatting (e.g., removing a with: block),
treat it as unchanged. Contributors should not feel obligated to address
pre-existing issues outside the scope of their contribution.

Files:

  • tests-unit/comfy_extras_test/nodes_string_test.py
  • comfy_extras/nodes_string.py
comfy_extras/**

⚙️ CodeRabbit configuration file

comfy_extras/**: Community-contributed extra nodes. Focus on:

  • Consistency with node patterns (INPUT_TYPES, RETURN_TYPES, FUNCTION, CATEGORY)
  • No breaking changes to existing node interfaces

Files:

  • comfy_extras/nodes_string.py
🧠 Learnings (6)
📚 Learning: 2026-02-21T14:01:41.482Z
Learnt from: pythongosssss
Repo: Comfy-Org/ComfyUI PR: 12555
File: comfy_extras/nodes_glsl.py:719-724
Timestamp: 2026-02-21T14:01:41.482Z
Learning: In PyOpenGL, bare Python scalars can be accepted for 1-element array parameters by NumberHandler. This means you can pass an int/float directly to OpenGL texture deletion (e.g., glDeleteTextures(tex)) without wrapping in a list. Verify function-specific expectations and ensure types match what the OpenGL call expects; use explicit lists only when the API requires an array.

Applied to files:

  • tests-unit/comfy_extras_test/nodes_string_test.py
  • comfy_extras/nodes_string.py
📚 Learning: 2026-07-13T17:26:10.852Z
Learnt from: silveroxides
Repo: Comfy-Org/ComfyUI PR: 14922
File: tests-unit/comfy_extras_test/test_qwen_visual_fusion.py:3-7
Timestamp: 2026-07-13T17:26:10.852Z
Learning: In Comfy unit tests that import CUDA-dependent modules (e.g., tests that need `comfy_extras/nodes_qwen.py`), set the global `cli_args.cpu = True` at module load time *before* importing `comfy_extras/nodes_qwen.py` when CUDA is unavailable. Do not rely on `pytest` fixtures or `monkeypatch` for this kind of import-time behavior, because fixtures run after the test module is imported/collected and the CUDA code would already execute. The goal is to prevent import-time CUDA initialization and keep the tests runnable in CPU-only environments.

Applied to files:

  • tests-unit/comfy_extras_test/nodes_string_test.py
📚 Learning: 2026-03-04T14:05:31.426Z
Learnt from: jtydhr88
Repo: Comfy-Org/ComfyUI PR: 12757
File: comfy_extras/nodes_custom_sampler.py:1069-1089
Timestamp: 2026-03-04T14:05:31.426Z
Learning: In the ComfyUI sampling pipeline, treat percent_to_sigma(0.0) as a sentinel value (999999999.9) that means starting from pure noise. This is consistent with BasicScheduler via calculate_sigmas. The SamplingPercentToSigma node’s return_actual_sigma flag differentiates this sentinel from sigma_max. Reviewers should not flag CurveToSigmas or similar nodes that rely on percent_to_sigma as bugs; downstream samplers are expected to handle the sentinel correctly. When reviewing related sampling-related code, assume this sentinel semantics unless there is explicit handling for a real sigma_max.

Applied to files:

  • comfy_extras/nodes_string.py
📚 Learning: 2026-04-04T13:29:15.653Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13258
File: comfy_extras/nodes_frame_interpolation.py:151-189
Timestamp: 2026-04-04T13:29:15.653Z
Learning: In this ComfyUI codebase, node `execute()` inference is already run under a global `torch.inference_mode()` context established in the execution engine (e.g., `execution.py` around line ~732). During review, avoid recommending changes that wrap node inference loops in `torch.inference_mode()`—it is already applied, so such suggestions are likely redundant.

Applied to files:

  • comfy_extras/nodes_string.py
📚 Learning: 2026-05-09T18:40:40.199Z
Learnt from: kijai
Repo: Comfy-Org/ComfyUI PR: 13813
File: comfy_extras/nodes_wandancer.py:868-872
Timestamp: 2026-05-09T18:40:40.199Z
Learning: When building video/temporal decoding nodes that call ComfyUI’s VAE.decode (comfy/sd.py), leverage VAE.decode’s existing VRAM-aware chunking along dim 0. Reshape or transpose the latent so the temporal dimension T is folded into dim 0 (e.g., transform a latent of shape [B, T, C, H, W] into [B*T, C, H, W] before calling vae.decode). This lets VAE.decode do chunked decoding without needing an explicit per-frame loop inside the node itself.

Applied to files:

  • comfy_extras/nodes_string.py
📚 Learning: 2026-05-20T00:10:14.673Z
Learnt from: Pauan
Repo: Comfy-Org/ComfyUI PR: 13997
File: comfy_extras/nodes_string.py:12-25
Timestamp: 2026-05-20T00:10:14.673Z
Learning: In the ComfyUI `comfy_extras/` codebase, some nodes intentionally ship with a default input string that references parameters that may not yet be connected. If the default would raise a `KeyError` (e.g., examples like `MathExpression` default `a + b`, or `StringFormat` default `{a}` with `min=0` and autogrow inputs), treat it as an intentional “hint default” UX pattern, not a bug. During review, do not flag this behavior or recommend changing `min` to `1` or altering the default to an empty string solely to avoid the `KeyError`.

Applied to files:

  • comfy_extras/nodes_string.py
🔇 Additional comments (2)
comfy_extras/nodes_string.py (1)

352-359: LGTM!

Also applies to: 365-371

tests-unit/comfy_extras_test/nodes_string_test.py (1)

1-8: LGTM!

Also applies to: 11-20, 23-40


📝 Walkthrough

Walkthrough

Updated RegexExtract to check capture-group values before returning or collecting them. Non-participating groups now produce an empty string in “First Group” mode and are omitted in “All Groups” mode. Added isolated unit tests covering module mocking, non-participating groups, mixed group participation, and normal extraction.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing RegexExtract handling of non-participating capture groups.
Description check ✅ Passed The description directly explains the bug, the fix, and the added tests, so it is clearly related to the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@vidigoat

Copy link
Copy Markdown
Contributor Author

I have read and agree to the Contributor License Agreement

comfy-legal added a commit to Comfy-Org/comfy-cla that referenced this pull request Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant