Comfy-Org/ComfyUI · error · Exception
floats_strength must be either an iterable input or a float,
Error message
floats_strength must be either an iterable input or a float, but was{type(floats_strength).__repr__}. What it means
Raised by create_hook_keyframes() in the ControlNet-style hook keyframe nodes: floats_strength must be a float/int (wrapped into a 1-element list) or an iterable of floats (one strength per keyframe). Anything else — a tensor, a string, None — falls through both branches and raises. Note the guard is type(floats_strength) in (float, int), so bool passes as int and numpy scalars fail.
Source
Thrown at comfy_extras/nodes_hooks.py:584
EXPERIMENTAL = True
RETURN_TYPES = ("HOOK_KEYFRAMES",)
RETURN_NAMES = ("HOOK_KF",)
CATEGORY = "advanced/hooks/scheduling"
FUNCTION = "create_hook_keyframes"
def create_hook_keyframes(self, floats_strength: Union[float, list[float]],
start_percent: float, end_percent: float,
prev_hook_kf: comfy.hooks.HookKeyframeGroup=None, print_keyframes=False):
if prev_hook_kf is None:
prev_hook_kf = comfy.hooks.HookKeyframeGroup()
prev_hook_kf = prev_hook_kf.clone()
if type(floats_strength) in (float, int):
floats_strength = [float(floats_strength)]
elif isinstance(floats_strength, Iterable):
pass
else:
raise Exception(f"floats_strength must be either an iterable input or a float, but was{type(floats_strength).__repr__}.")
percents = comfy.hooks.InterpolationMethod.get_weights(num_from=start_percent, num_to=end_percent, length=len(floats_strength),
method=comfy.hooks.InterpolationMethod.LINEAR)
is_first = True
for percent, strength in zip(percents, floats_strength):
guarantee_steps = 0
if is_first:
guarantee_steps = 1
is_first = False
prev_hook_kf.add(comfy.hooks.HookKeyframe(strength=strength, start_percent=percent, guarantee_steps=guarantee_steps))
if print_keyframes:
logging.info(f"Hook Keyframe - start_percent:{percent} = {strength}")
return (prev_hook_kf,)
#------------------------------------------
###########################################
class SetModelHooksOnCond:View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Pass a plain Python float (e.g. 1.0) or a list of floats like [1.0, 0.8, 0.5].
- Convert upstream values before the call: float(x) for scalars, [float(v) for v in x] for sequences.
- If the value comes from a custom node output, fix that node to emit FLOAT, not tensor/string.
Example fix
// before strength = tensor_mean # torch tensor -> raises create_hook_keyframes(strength, 0.0, 1.0) // after strength = float(tensor_mean.item()) create_hook_keyframes(strength, 0.0, 1.0)
Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Iterable
strength = float(strength) if isinstance(strength, (int, float)) else [float(v) for v in strength] if isinstance(strength, Iterable) else None
if strength is None:
raise TypeError(f"floats_strength has unsupported type {type(strength).__name__}") Type guard
def is_valid_strength(x) -> bool:
return isinstance(x, (int, float)) or (isinstance(x, (list, tuple)) and all(isinstance(v, (int, float)) for v in x)) Try / catch
try:
kfs = create_hook_keyframes(strength, start, end)
except Exception as e:
if "floats_strength" in str(e):
kfs = create_hook_keyframes(float(strength), start, end) # coerce and retry once
else:
raise Prevention
- Always convert upstream values to plain Python floats before calling hook keyframe APIs.
- Custom nodes should validate Autogrow strength inputs are FLOAT before forwarding.
- Remember numpy scalars and tensors are rejected — call .item()/float() first.
When it happens
Trigger: Connecting a non-float source to the strength input (e.g. a STRING node, a CONDITIONING, or a torch tensor from a custom node); passing a numpy float32 scalar (not a Python float and not Iterable); passing None because the optional input was left unconnected and forwarded as-is by custom glue code.
Common situations: Custom nodes that reuse create_hook_keyframes with unvalidated upstream values; feeding tensor data from math nodes that output tensors instead of floats.
Related errors
- Control type {max_type_name}({max_type}) is out of range for
- Need at least {require_count} hooks to combine, but only had
- Unrecognized interpolation method '{method}'.
- Cannot convert type {type(value).__name__} to {cls.__name__}
- Qwen Fun ControlNet requires a control hint image.
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/9bcbc863a916150d.
Report an issue: GitHub.