Godot 4.3 Signals Not Firing - Connection and Binding Fix (How to Fix)

You connected a signal in Godot 4.3 but the connected function never runs when the signal is emitted. The game runs without errors, but the behavior you expected from the signal does not happen. This can be frustrating when you are sure the connection was made.

This guide explains why Godot 4.3 signals sometimes do not fire after connection and how to fix connection, binding, and timing issues. By the end, you will know how to connect signals correctly and verify they work.

The Problem

Common symptoms:

  • Signal connected but callback never runs – You call connect() and nothing happens when the signal is emitted.
  • Signal worked in Godot 3.x but not in 4.3 – Old connection style or node paths no longer work.
  • Signal fires once then stops – Often due to scene change or node being freed.
  • No error message – Connection appears to succeed but the callable is never invoked.
  • Signal fires on wrong object – Callback runs on a different node than intended.

These usually point to how or when the signal was connected, or to the lifetime of the nodes involved.

Why This Happens

Connection timing and lifecycle

  • The receiver or emitter is not ready when you connect. In Godot 4, both nodes should exist and, when possible, have had _ready() run before you connect.
  • You connect in _ready() but the emitting node is a child that is not ready yet, so the connection can fail or the emitter is invalid.
  • After a scene change, nodes from the old scene are freed and their signals are disconnected. If you keep a reference to an old node and emit from it, nothing will receive it.

Wrong connection target or callable

  • You pass a string (e.g. "method_name") instead of a Callable (e.g. method_name or self.method_name). Godot 4 uses Callables; string-based connection is deprecated or not valid for the API you are using.
  • The callable is bound to the wrong object (e.g. a freed node) or the method does not exist on the node that receives the signal.
  • Typo in method name – The method you pass to connect() does not exist on the target object, so the callable is invalid.

Node path and references

  • You use get_node() or $NodePath and the path is wrong after a scene or node change, so you connect to the wrong node or to nothing.
  • You hold a reference to a node that gets freed (e.g. after changing scene), then emit or connect from that reference.

Binding and extra arguments

  • In Godot 4 you use .bind(args) for extra arguments. If you use the wrong number or order of arguments, the callback may not match the signal signature and can be skipped or error in a way that looks like "signal not firing."
  • Passing a callable that expects different parameters than the signal provides can cause runtime errors or no call.

Editor vs code

  • You connected the signal in the Editor (Signals tab) but the node path or script method changed, so the connection points to a missing or wrong method.
  • You connect in code but the node order or scene tree is different at runtime (e.g. instanced scene), so the emitter or receiver is not the one you expect.

Solution 1: Connect with Callables (Godot 4 Syntax)

In Godot 4 and 4.3, signals are connected using Callables, not strings.

Step 1: Use the Correct Connect Form

Correct (Callable):

# Connect to a method on self
emitter.signal_name.connect(_on_signal_name)

# Connect to a method on another node
emitter.signal_name.connect(target_node._on_signal_name)

# With extra arguments using bind()
emitter.signal_name.connect(_on_signal_name.bind(my_arg))

Incorrect (old or invalid):

# Do NOT rely on string method names for connect()
emitter.signal_name.connect("_on_signal_name")  # Deprecated / may not work as expected

Step 2: Ensure the Method Exists and Matches

  1. The target method must exist on the object you pass (e.g. self or target_node).
  2. The method signature should match the signal (same number and types of parameters), or use .bind() to supply extra arguments so the remaining parameters match the signal.

Verification: Add a print() at the start of the callback. Run the game and trigger the signal. If the print runs, the connection and emission work; if not, the problem is connection, timing, or node lifetime.

Solution 2: Fix Connection Timing (Use _ready() and Node Order)

Signals should be connected when both the emitter and the receiver exist and are in the tree. For many cases, connecting in _ready() is sufficient, but the order of _ready() calls depends on the scene tree (parent before children).

Step 1: Connect After Nodes Are Ready

Connect in _ready() and ensure you are not depending on a child that has not run its _ready() yet:

func _ready() -> void:
    # If the emitter is a child, it already exists when parent's _ready() runs
    var button = $Button
    if button:
        button.pressed.connect(_on_button_pressed)

Step 2: If the Emitter Is Created at Runtime

If you create the emitter node in code (e.g. instantiate() and add_child()`), connect after adding it to the tree so it is ready:

var new_node = scene.instantiate()
add_child(new_node)
# Connect after add_child so the node is in the tree and ready
new_node.signal_name.connect(_on_signal_name)

Verification: Again, use a print() in the callback to confirm it runs when you expect.

Solution 3: Do Not Rely on Freed Nodes

When you change scenes or remove nodes, they are freed and their signals no longer reach valid receivers. If you keep a reference to an old node and emit from it, nothing will happen.

Step 1: Connect and Emit Within the Same Scene Lifecycle

  • Connect signals when both nodes are in the current scene tree.
  • Do not keep references to nodes from a previous scene and expect their signals to work after a scene change.

Step 2: Use Scene Tree Lifecycle

If you need to react to scene changes, use the scene tree API (e.g. tree_exiting, or signals on the node that is not freed) instead of holding references to nodes that get freed.

Verification: After a scene change, do not call methods or emit on nodes from the old scene. If your logic depends on that, move the logic to a node that persists (e.g. autoload) or to the new scene.

Solution 4: Check Node Paths and References

Wrong node paths or stale references can make it seem like "signals don't fire."

Step 1: Resolve Emitter and Receiver Correctly

  1. Use get_node() or $NodePath with a path that is valid at the time you connect.
  2. If the node is inside an instanced scene, the path must reflect the actual tree (e.g. $SubScene/Button not just $Button).
  3. Print the node reference to debug: print(emitter) and print(receiver) to ensure they are non-null and the right types.

Step 2: Prefer Unique Names or Direct References

If you have dynamic or duplicated scenes, avoid fragile paths. Use unique names in the editor or store a direct reference when you instantiate:

var my_button = $SubScene/Button
my_button.pressed.connect(_on_button_pressed)

Verification: Ensure emitter and the connection target are the nodes you expect. A simple print() in the callback confirms the connection and emission.

Solution 5: Binding and Extra Arguments

If your callback needs extra arguments, use .bind() so the callable still matches the signal’s parameter list.

Step 1: Match the Signal Signature

Your callback can have more parameters than the signal if you bind the extra ones:

# Signal: emitted_with_one_arg(value)
# Callback: _on_signal(value, my_extra)
emitter.emitted_with_one_arg.connect(_on_signal.bind(my_extra))

func _on_signal(value: int, my_extra: String) -> void:
    print(value, my_extra)

Step 2: Do Not Mismatch Parameter Count

If the signal emits two arguments and your callable expects one (and you did not bind one), the call can fail or not run. Adjust the callback or use .bind() so the remaining parameters match.

Verification: Call the callback manually from the editor or a test script with the same arguments the signal emits. If it runs when called directly but not when the signal fires, the issue is connection or emission.

Alternative Fixes

Reconnect in the editor: If you connected in the Editor and the script or node changed, remove the old connection and reconnect the signal to the correct method on the correct node.

Use Callable explicitly: If you are building the callable dynamically, use Callable(object, "method_name") and ensure object is valid and has that method.

Debug emission: Temporarily add print("emitting") where you emit the signal. If "emitting" prints but the callback does not run, the problem is the connection or the receiver. If "emitting" does not print, the problem is that the signal is never emitted.

Prevention Tips

  • Always use Callables for connect() in Godot 4/4.3; avoid string-based connection for new code.
  • Connect in _ready() (or after adding runtime nodes) so both sides exist and are in the tree.
  • Avoid keeping references to freed nodes; do not emit or connect from nodes that have been removed or freed.
  • Use print() in callbacks during development to confirm signals fire.
  • Check the Signals tab in the editor for the node to see which signals exist and how they are connected.

Related Problems and Links

Official documentation:

Bookmark this fix for quick reference when debugging signals. If this article helped, share it with other Godot devs. If your signals still do not fire after trying these steps, double-check the Signals tab in the editor and the exact node/method you are connecting in code.