Closed hobojoker closed 1 year ago
Hmm. Can you share an example workflow json? Muting works a bit differently than outright disconnecting, sometimes feels a bit backwards.
I actually saw this in a recent reddit comment too - apparently there is a thing in ComfyUI where if a node is connected it has to execute basically, so you can't feed a null input to stop something from running:
Here is an example of using these 'break' nodes to stop execution:
when trying to keep that same functionality (muting all inputs to a node to stop it executing) I get an error instead:
This one is a little confusing at first:
Basically I have 2 different context (buttons) that I use to trigger whether or not this large merge model preset run through a sampler - but if I turn both off, then instead of just not running, I get an error from the nodes. I needed to put in another context node in front of the that switch, and then mute that in order for it to not throw an error.
tldr; 2x Muted Context -> Switch -> (stuff) = ERROR 2x Muted Context -> Switch -> Muted Context = Doesn't Run (intended!) - no error fully functional with 1 or both context active
I guess another method would be for a switch to mute itself if all context are null, and unmute itself if a context triggers it? I don't know if things can be that dynamic or not...
Error example when context in front of switch is removed and both inputs are muted:
Yea, so that's right that if a node is connected, it gets serialized in the graph and, if muted, gets "skipped" ...which is a different flow from disconnecting the node all together.
The switch is made to provide a value, not to stop execution (that's what the "fast muter" does via muting).
I do think you can save a step, which is instead of having to put a Muted Context after the Switch, you could just mute the Switch itself. I think that would work the same way. But, then, instead of muting the two inputs when you want to stop execution, you would need to mute the switch itself.
I'm pretty sure ComfyUI doesn't allow me to hook into the serialization flow to fix this seamlessly, but I'll still take a look to see if there's a way to handle this without having to manually mute the switch itself.
I think the way to implement it would be to essentially add the functionality to the switches so that they work like a collector -> therefore when the switch is hooked up to a fast muter, when the final input is muted, it also mutes the switch itself through internal logic - that way it isn't dynamic or anything and is just linked to the function call of the mute toggle.
That at least makes sense to me, I implemented my own 'mute all' node to mute all connected nodes, and based on what I've understood from trying to implement that, this would be the easiest method... whether or not the most clean or properly implemented is another question.
Yea, that's one way but it's not as clear to the user which I hate when software does things like that. What I hoped to do was not actually mute the node, but when it's asked to be serialized, pretend it's muted... but ComfyUI doesn't let me inspect that process.
However, I can't reproduce muting an in between context node working, which means, even the above auto-muting wouldn't work. In my test workflow, whether or not I mute a context in between node, the context switch itself, or even disconnect the noodles I always get an error. This is similar to what I was saying before (and tried to explain in the README as well)...
Switches (and muting) cannot replicate "disconnecting" the next step, so a workflow doesn't continue. In order to have optional workflows you need to mute/disconnect the output node (or an attached node to that output node between the output and a "worker" node, like a sampler).
How it needs to work is you need to "disconnect" any output node (any at all, Preview Image, Save Image, etc. but even 'Display Int' and more) from any previous node that is going to be requiring an input. So, instead of muting all the switch inputs, or even the switch itself, if you want to skip the entire next part of your workflow, you need to mute whatever and all output nodes its attached to (or, mute the node right before the output node).
In the above, if we want to skip this "Sampler" workflow and continue the workflow with its other valid, offscreen outputs without an error, we need to "disconnect" that "Preview" output node from Decode and Sampler nodes, as they require inputs. We can do that by muting the Preview node itself, or muting the Context node right before (in purple). (Note, if the purple Ctx node is muted, the Preview node will have a red border but will not throw up an error as long as there are other valid output nodes to be worked out within the graph.)
If we were to mute BOTH the orange colored Ctxs going into the Switch before the "Sampler" group, or the Switch itself, an error will be thrown as the graph is trying to do the work for that Preview output node, but is given null data. We want to skip those nodes by working backwards from the output node, rather than muting nodes moving forward through the graph; which is arguably more intuitive and, thus, harder to grasp at first. (Note that you can mute the switch and orange nodes, but you would also HAVE to mute/disconnect the output node as well to avoid an error popping up)
Here's another example where we've muted the entire "Sampler" group from running by disconnecting the output context, but also have that feed into a switch to go onto to the next steps of the workflow. No error is thrown because we have a valid output node on the right (though, the Sampler's preview node does silently have a red border).
I hope that explanation helps. It's hard to grasp and even I forgot as I was writing my previous reply.
Aside, I'm planning to add a node that combines nodes into one mutable toggle on the Fast Muter (that's why I renamed "Node Combiner" to "Node Collector" to help clarify the new, future node). While that won't solve this issue outright, it will make it simpler to have just one switch that can mute several nodes at once.
Hmmm, while I hear what you are saying, it's conflicting with the processes that I have in place.
I should maybe clarify what I mean when I say an error - what I mean is not a printed ignored message, but specifically a critical error that stops the process with a popup that I showed in the above post:
(don't care about these at all)
I have a setup where I basically reuse the same output for multiple different process paths, I made essentially a dashboard, where I have my inputs and outputs, with mute toggles on the left which determine what actually populates them. This is powered by your context, and context switch nodes.
I never toggle the outputs off and I do not get any errors as long as I do what I indicated in the screenshots and put a context node after a switch to actually toggle the switch off when all switches are null. My standard method of disabling functions is not to disconnect the outputs, but to disconnect the model or image input to a process (this way it's just 1 connection, since typically I have 3 - 5 outputs per model input) -> which has always worked out for me, and can clearly be seen in the first image I posted with those model inputs highlighted that brake feeding into that inpainting loop with 4 outputs (not using ctx there as that was a test workflow I was in the middle of working on).
Oh, I just thought of something. The way that you mute things might be the problem - because ComfyUI doesn't re-run processes that haven't changed, but because when you are muting you are changing something (rather than using the in-build mute function) it tries to re-run the following nodes, but with a null input.
The way I tested this:
Process Using CTX Mute:
Queue the prompt -> Runs through properly
If I toggle off CTX on the Fast Muter and then Queue -> it properly blocks the execution of that part with no issues
If I toggle back on the CTX on the Fast Muter and then Queue -> it reruns the process that it goes into, even though nothing has changed except toggling the CTX (incorrect behavior for mute)
Process Using Built-in Mute:
Queue the prompt -> Runs through properly
If I Mute ReRoute1 using ctrl+M - and then Queue -> it properly blocks the execution of that part with no issues
If I UnMute ReRoute1 using ctrl+M and then Queue -> it does not re-process because there has been no change to the input (expected behavior!)
That's pretty conclusive to me. I think you don't see this in your workflow because you mute in between the process -> output, whereas I mute between the input -> process.
(Just FYI, the reason I mute the input is because I use some 'smart' custom nodes which process images internally, so muting the output doesn't prevent them from processing)
It would be ok if ComfyUi could support mute for "group".
The way that you mute things might be the problem - because ComfyUI doesn't re-run processes that haven't changed, but because when you are muting you are changing something (rather than using the in-build mute function) it tries to re-run the following nodes, but with a null input.
The muter/bypass doesn't mute any differently than ctrl+M/B shortcuts, or selecting from the menu. It's all the same code.
The way I tested this:
- Image -> reroute1 -> ctx -> reroute2 -> Intended Node
Process Using CTX Mute:
- Queue the prompt -> Runs through properly
- If I toggle off CTX on the Fast Muter and then Queue -> it properly blocks the execution of that part with no issues
- If I toggle back on the CTX on the Fast Muter and then Queue -> it reruns the process that it goes into, even though nothing has changed except toggling the CTX (incorrect behavior for mute)
Process Using Built-in Mute:
- Queue the prompt -> Runs through properly
- If I Mute ReRoute1 using ctrl+M - and then Queue -> it properly blocks the execution of that part with no issues
- If I UnMute ReRoute1 using ctrl+M and then Queue -> it does not re-process because there has been no change to the input (expected behavior!)
That's pretty conclusive to me.
The processes above look different; it sounds like you're muting the context in your first process, but the reroute node in the latter. I've found that muting reroute nodes actually don't do anything (even the base Comfy ones). So in your second process you actually didn't change the flow at all between those three steps, since muting a reroute doesn't do anything and, since nothing changed between those three queues, nothing had to re-run in step 2 or step 3 (which made it seem like step 3 re-used step 1 but, really, step 2 didn't change anything).
If you were to mute the CTX node manually with ctrl+m in the second process like you did in the first process with the fast muter, it would re-process on step three just like Fast Muting does.
I think you don't see this in your workflow because you mute in between the process -> output, whereas I mute between the input -> process.
Yea, muting in between process & output is really the only way to cut off paths in Comfy. AFAICT, this isn't unique to any of the rgthree-comfy nodes, it's just the way Comfy's graphing node serialization works; even with just normal muting and serialization w/o any special nodes.
(Just FYI, the reason I mute the input is because I use some 'smart' custom nodes which process images internally, so muting the output doesn't prevent them from processing)
This could be the problem. Obviously if you have a process + output node combo that requires an input and aren't feeding the input, I think it's unavoidable it's going to complain. If you can slim down your workflow into something that is repeatable, I'm happy to try to take a look, but it feels like it's just the way Comfy is set up to work.
Oh, you're totally right, my testing was flawed! Sorry for jumping to conclusions, but I appreciate your patience, when muting the same node (ctx) then the process will re-run, just as you said.
So the remaining part of the issue is still relevant though the: CTX -> CTX Switch = error when all CTX into a switch are muted.
Because the switch itself isn't muted, it still passes through a null input. If the workaround is if you mute all inputs make sure you also mute your switch that's fine, it would just be more elegant for the switch to contextually recognize that case.
For the record, muting an input is still an effective method for controlling your workflow and for stopping processes, and is much cleaner than muting outputs if you have a bunch of previews and multiple outputs, but you are absolutely correct that it is way more efficient to mute outputs, because then processes will not re-run when muted/unmuted unless an input is changed.
tldr; If the workaround is if you mute all inputs make sure you also mute your switch then this issue is resolved, but I would definitely appreciate if you could take a look at contextually muting the switch itself, as I believe that to be an effective solution to prevent errors.
I think I understand what could be happening; if your output and process node are bundled, then you can't really "disconnect" them. It must have worked when muting an inbetween-ctx node (or, the switch itself) because the next mode must be the output/process combo node and, since output node errors are supressed if there's another valid output path, it just kinda works; kind of by accident.
Right now, I believe auto muting the switch would not be beneficial to most workflows because if the switch is fed two null paths, then it really is a workflow error and a user may want to know that their workflow is broken, rather than it be suppressed out from under them.
However, I do like having advanced tools to work around this. So, I created some powerful nodes to mute/bypass based on other nodes status.
Check out the "Mute / Bypass Repeater" and the "Mute / Bypass Relay".
@hobojoker - You should be able to use them to automatically mute the Switch when both of your other nodes are muted. It does add two nodes so it's not clean as the Switch auto-muting itself, but it's far more robust (like, being able to mute a far-away node, etc).
Normally I can turn off functionality by breaking the input connection to a part of the circuit I don't want to run - I can't do that with just a context switch though by disabling the inputs - it will stop the process and throw an error - I'm required to put another context block after the switch and mute that instead. This is overly complicated and frustrating, especially without any logic blocks or the ability to disable multiple blocks with one click to work around it more easily.