FyroxEngine/Fyrox · warning

There is a script instance on a node

Error message

There is a script instance on a node {}, but no message sender. The script won't be correctly destroyed!

What it means

When a scene node is destroyed, each of its script instances should receive a DestroyScriptMessage via the engine's message sender so the script can clean up. If the node has a script instance but no message sender is available at that point, Fyrox logs this warning because the script's destructor logic won't run. Resources held by the script (entities, GPU handles, network connections) may leak.

Solutions

  1. Ensure nodes with scripts are destroyed via the normal Scene API (remove_node) during the update loop so a message sender is present.
  2. Avoid destroying scripted nodes during graph destruction/shutdown; free resources in the script's on_removed or Drop if teardown-time destruction is unavoidable.
  3. Review custom code paths that clone/detach ScriptDecompile logic without propagating the sender.
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Deleting a node (or its subtree) whose Script Decompile path executes while self message sender is None — e.g. destroying nodes during graph teardown phases where the sender was already dropped or never provided.

Common situations: Removing nodes during engine shutdown or inside another script's teardown; constructing/destroying nodes outside the normal update loop where the message sender context is unavailable.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/a8a140dfa2866133. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-impl/src/scene/base.rs:895

    /// update tick of the parent graph.
    pub fn remove_script(&mut self, index: usize) {
        // Send script to the graph to destroy script instances correctly.
        if let Some(entry) = self.scripts.get_mut(index) {
            entry.should_be_deleted = true;

            // We might be in a middle of a script method execution, where script is temporarily
            // extracted from the array.
            if let Some(script) = entry.take() {
                if let Some(senders) = self.senders.as_ref() {
                    Log::verify(senders.script_message_sender.send(
                        NodeScriptMessage::DestroyScript {
                            script,
                            handle: self.self_handle,
                            script_index: index,
                        },
                    ));
                } else {
                    Log::warn(format!(
                        "There is a script instance on a node {}, but no message sender. \
                    The script won't be correctly destroyed!",
                        self.name(),
                    ));
                }
            }
        }
    }

    /// Removes all assigned scripts from the scene node. The scripts will be removed from
    /// first-to-last order an their actual destruction will happen either on the current update tick
    /// of the parent graph (if it was removed from some other script) or in the next update tick.
    pub fn remove_all_scripts(&mut self) {
        let script_count = self.scripts.len();
        for i in 0..script_count {
            self.remove_script(i);
        }
    }

View on GitHub (pinned to 76c91aad8e)