Zum Inhalt

Fehlersuche & FAQ

Kursstartseite

Diese Seite sammelt häufige Fehler, Warnungen und Fragen rund ums Setup und Training von RL-Agenten mit godot-native-rl, stable-baselines3 und Python — plus die Legacy-Beispiele von godot-rl-agents, die noch nicht migrierte Einheiten nutzen. Jeder Eintrag erklärt Ursache und Fix. Hier zuerst nachsehen, bevor du ein GitHub-Issue öffnest.


Setup & Installation

NcnnSync / NcnnAIController3D nicht unter „Node hinzufügen" zu finden

Ursache: Das Addon ist nicht installiert. Es liegt nicht im Kurs-Repo, ein frischer Klon hat also gar kein addons/godot_native_rl/ — oder du hast ein anderes Projekt geöffnet, oder der erste Projekt-Import ist noch nicht abgeschlossen.

Fix:

scripts/fetch-native-runner.sh            # installiert das gepinnte Addon-Release
scripts/fetch-native-runner.sh --check    # zeigt gepinnt vs. installiert

Danach in Godot: Import → godot-rl-course/examples/neural_foundations/game/project.godot, den ersten Import durchlaufen lassen und erneut Node hinzufügen → NcnnSync suchen. Es wird nichts kompiliert, der Import geht also schnell.

Wenn du das Addon in deinem eigenen Projekt nutzt, prüfe, ob addons/godot_native_rl/ in den addons/-Ordner dieses Projekts kopiert wurde.

Siehe auch: Unit 0 § 3


„NcnnRunner"-Klasse fehlt / native Inferenz lädt nicht

Ursache: Die native ncnn-Inferenz benötigt eine Plattform-Bibliothek (GDExtension). Diese Bibliotheken liegen nicht im Kurs-Repo — sie sind größer als alles andere darin — ein frischer Klon hat sie also nicht, bis du sie installierst.

Fix: Führe den Installer aus dem Repo-Stammverzeichnis aus:

scripts/fetch-native-runner.sh
scripts/fetch-native-runner.sh --check    # zeigt gepinnt vs. installiert

Er liefert macOS Apple Silicon, Windows x86_64 und Linux x86_64 mit, alle Desktop-Plattformen sind also abgedeckt. Schlägt es danach weiterhin fehl, prüfe deine Godot-Version: die Extension verlangt 4.5 oder neuer und registriert sich auf älteren Versionen stillschweigend nicht. Das Training ist in jedem Fall nicht betroffen — die Trainings-Bridge ist GDScript und braucht keine native Bibliothek.


Godot-Versionskompatibilitätsfehler

Ursache: Die gebündelte ncnn-GDExtension deklariert compatibility_minimum = 4.5; ältere Godot-Versionen laden das Projekt nicht sauber.

Fix:

# Lade Godot 4.5 oder neuer (Standard-Version) von godotengine.org herunter
# Auf der Kommandozeile prüfen:
godot --version

Die Legacy-Beispiele von godot-rl-agents, die ab RL Essentials genutzt werden, haben eigene Versionsanforderungen — prüfe das godot-rl-agents-Repo, wenn ein Beispielprojekt Probleme macht.


ModuleNotFoundError: No module named 'godot_rl' — oder gdrl: command not found

Ursache: Das Python-Paket godot-rl ist nicht installiert oder deine conda-Umgebung ist nicht aktiv. (Der Kurs nutzt den Befehl gdrl selbst nicht — siehe Referenz — sein Fehlen ist aber dasselbe Symptom.)

Fix:

# Activate your conda environment
conda activate godot_env

# Install using the pinned requirements file (recommended)
pip install -r requirements-course.txt

# Verify (expect 0.8.2 — there is no `gdrl --version`)
python -c "import importlib.metadata as m; print(m.version('godot-rl'))"

Paketname ist godot-rl, nicht godot-rl-agents

Das PyPI-Paket heißt godot-rl (Installation via pip install godot-rl oder requirements-course.txt). Der alte Name godot-rl-agents ist nicht mehr der kanonische Paketname. Der Python-Import bleibt import godot_rl.


ModuleNotFoundError: No module named 'stable_baselines3'

Ursache: stable-baselines3 ist im aktiven Python-Env nicht installiert.

Fix:

conda activate godot_env
pip install stable-baselines3

Bei Berechtigungsfehler: pip install --user stable-baselines3 oder prüfen, dass dir /usr/local/lib/python3.x/ gehört.


ModuleNotFoundError: No module named 'godot_rl'

Ursache: Das Paket godot-rl ist in deiner aktiven conda-Umgebung nicht installiert.

Fix:

conda activate godot_env
pip install -r requirements-course.txt

Verifizieren:

python -c "import godot_rl; print(godot_rl.__version__)"


Python-Versions-Inkompatibilität (godot-rl braucht Python 3.8+)

Ursache: Dein Python-Env ist älter als 3.8, oder du nutzt Python 2.

Fix:

# Check your Python version
python --version

# If < 3.8, create a new conda environment with Python 3.10
conda create -n godot_env python=3.10
conda activate godot_env
pip install -r requirements-course.txt


onnxruntime nicht installiert (ONNX-Inferenz schlägt fehl)

Ursache: onnxruntime wird für ONNX-Export/-Ausführung benötigt, aber nicht automatisch mit stable-baselines3 installiert.

Fix:

conda activate godot_env
pip install onnxruntime
# or for GPU support
pip install onnxruntime-gpu


Training startet nicht

NcnnSync: minor version mismatch (got 3, expected 7)

Ursache: In deinem godot_env steckt noch ein altes godot-rl. Protokoll 0.7 sprechen sowohl NcnnSync als auch die godot_rl_agents-Beispiele; godot-rl-Releases vor 0.8 sprechen 0.3. Der Handshake warnt und läuft weiter, das Training funktioniert also — die Umgebung passt aber nicht mehr zum Kurs.

Fix: Installiere die gepinnten Versionen neu:

conda activate godot_env
pip install -r requirements-course.txt
python -c "import godot_rl.core.godot_env as g; print(g.GodotEnv.MINOR_VERSION)"   # erwartet: 7

Ein echtes Hängenbleiben (nach einer Minute keine Rollout-Tabellen) ist ein anderes Problem — siehe den nächsten Eintrag.

Siehe auch: Unit 0 § 4


WebSocket-Verbindung verweigert / ConnectionRefusedError: [Errno 111]

Ursache: Das Python-Skript versucht sich auf Port 11008 (Default) mit Godot zu verbinden, aber Godot läuft nicht, lauscht nicht oder ist auf einem anderen Port.

Fix:

# 1. Start the PYTHON side first — it opens the socket and waits.
#    Godot is the side that connects, so nothing can connect to a server
#    that is not listening yet.
conda activate godot_env
python stable_baselines3_example.py --experiment_name=debug --viz

# 2. Wait for "waiting for remote GODOT connection on port 11008",
#    then press F6 (Play Scene) in the Godot editor — or pass
#    --env_path=./godot_binary in step 1 to let the script launch it.

# 3. If using a custom port, ensure both sides match
# In Python: env = GodotEnv(..., port=12000)
# In Godot: AIController.port = 12000

Sicherstellen, dass kein anderer Prozess Port 11008 blockiert:

lsof -i :11008   # macOS / Linux
# Windows (PowerShell):
# netstat -ano | findstr :11008

Windows: Antivirus blockiert eventuell still Port 11008

Unter Windows blocken Windows Defender und Dritt-Antivirus-Software den godot-rl-Socket-Port manchmal lautlos. Verbindet sich Godot trotz freien Ports nie, Firewall-Ausnahmen für python.exe und die Godot-Executable hinzufügen. Siehe Windows-Erststart für eine Schritt-für-Schritt-Anleitung.


„Action space mismatch" / ValueError: Action space size mismatch

Ursache: Die Anzahl der Aktionen deines AIControllers (n_actions) stimmt nicht mit dem n_actions-Argument deines SB3-Algorithmus überein.

Fix:

# In AIController.cs (or your Godot script)
# Count the exact actions you return
public override int GetActionSpaceSize() {
    return 2;  // e.g., 2 for move_x, move_y
}

# In your Python training script, match exactly
model = PPO(
    "MlpPolicy",
    env,
    n_steps=2048,
    ...
)

Beide drucken, um sicherzugehen:

print("Python action space:", env.action_space.shape)
print("Godot n_actions:", env._get_obs()['n_actions'])  # or query your AIController


KeyError: 'obs' beim Trainingsstart

Ursache: Dein Beobachtungs-Dictionary aus Godot enthält den 'obs'-Key nicht oder nutzt den falschen Namen.

Fix:

# In your AIController, ensure you return a dictionary with 'obs' key
public override Dictionary<string, object> GetObservation() {
    return new Dictionary<string, object> {
        { "obs", new float[] { position.X, position.Y, ... } }
    };
}

# In Python, access it as
obs = env.reset()
print(obs.keys())  # should include 'obs'

Gibst du ein flaches Array statt eines Dicts zurück, wrappen:

return {"obs": observation_array}


Training friert nach dem ersten Rollout ein (stiller Godot-Crash)

Ursache: Der Godot-Prozess ist abgestürzt oder hängt, aber Python hat den Fehler nicht empfangen. Häufig durch eine Exception in _process() oder _physics_process().

Fix:

# 1. Run Godot itself in the foreground to see stderr/logs
#    (`gdrl` is the Python side — it never starts Godot)
godot --path examples/BallChase 2>&1 | tee godot.log

# 2. Check the Godot log for exceptions
# Common culprits: accessing null nodes, division by zero, infinite loops in reward calculation

# 3. Add debug prints in AIController
GD.Print($"Step {_step_count}: obs={obs}, action={action}, reward={reward}");


RuntimeError: Expected all tensors to be on the same device (PyTorch-Fehler)

Ursache: Deine Beobachtung oder Belohnung ist ein PyTorch-Tensor auf der CPU, aber PyTorch erwartet alle Tensoren auf demselben Gerät (CPU oder GPU).

Fix:

# Ensure all observations and rewards are NumPy arrays or the same tensor device
def _get_obs(self):
    obs = np.array([...], dtype=np.float32)  # Use NumPy, not torch
    return obs

# Or, if using PyTorch tensors, ensure they are all on the same device
obs = obs.to(device)  # Move to correct device


Training läuft, lernt aber nicht

NaN-Loss nach ein paar tausend Schritten

Ursache: Lernrate zu hoch, Belohnung unbeschränkt oder Pixel-Beobachtungen nicht normalisiert. Führt zu explodierenden Gradienten.

Fix:

# Reduce the learning rate
model = PPO("MlpPolicy", env, learning_rate=1e-4)  # Instead of 1e-3 or higher

# Ensure rewards are bounded (e.g., -1 to 1)
reward = np.clip(reward, -1.0, 1.0)

# Normalize pixel observations to [0, 1] or [-1, 1]
observation = observation.astype(np.float32) / 255.0


ep_rew_mean bleibt ewig flach bei 0 oder negativ

Ursache: Deine Belohnungsfunktion gibt jeden Schritt 0 (oder einen sehr kleinen Wert) zurück — der Agent hat kein Lernsignal. Prüfe das Vorzeichen — negative Belohnungen entmutigen.

Fix:

// In AIController: reward should be non-zero when the agent makes progress
float reward = 0.0f;
if (Vector2.Distance(transform.GlobalPosition, target.GlobalPosition) < 1.0f) {
    reward = 1.0f;  // Goal reached
} else {
    reward = -0.01f;  // Small step cost to encourage progress
}

return reward;

Belohnungen für TensorBoard loggen, um zu debuggen:

# In your training script, log rewards per episode
episode_rewards.append(total_reward)
logger.record("custom/episode_reward", total_reward)


ep_rew_mean oszilliert wild und bessert sich nie

Ursache: Lernrate zu hoch oder n_steps zu klein für PPO, um vor jedem Update genug Erfahrung zu sammeln.

Fix:

# Increase n_steps (experience per update)
model = PPO(
    "MlpPolicy",
    env,
    n_steps=4096,     # Instead of 2048
    learning_rate=3e-4,  # Reduce if still unstable
    ent_coef=0.01,    # Increase entropy coefficient to encourage exploration
)

Länger trainieren und Trends in TensorBoard über 100k+ Schritte ansehen, nicht nur die ersten 10k.


RuntimeError: CUDA out of memory (GPU-Fehler)

Ursache: Batch-Größe zu groß für den GPU-Speicher, oder zu viele parallele Umgebungen ohne genug VRAM.

Fix:

# Reduce the buffer size and batch size
model = PPO(
    "MlpPolicy",
    env,
    n_steps=1024,    # Smaller rollout buffer
    batch_size=64,   # Smaller training batch
)

# Or, use CPU only
env = DummyVecEnv([lambda: GodotEnv(..., use_discrete_actions=False)])  # CPU training


Agent dreht sich auf der Stelle / tut nichts (Aktion ignoriert)

Ursache: Aktionsraum in Godot falsch gemappt oder Aktionen werden nicht auf den Physikkörper angewandt.

Fix:

// In AIController: ensure actions are applied each frame
public override void SetAction(float[] action) {
    // action[0] and action[1] are continuous or discrete actions
    velocity.X = action[0] * max_speed;
    velocity.Y = action[1] * max_speed;
    _body.Velocity = velocity;
    _body.MoveAndSlide();
}

// Check that you call MoveAndSlide() in _physics_process
public override void _PhysicsProcess(float delta) {
    SetAction(_last_action);
    _body.Velocity = velocity;
    _body.MoveAndSlide();
}


Entropie kollabiert früh fast auf null (Policy wird deterministisch)

Ursache: ent_coef zu klein oder die Policy ist auf deterministisches Verhalten konvergiert, bevor sie die Aufgabe gelernt hat.

Fix:

# Increase entropy coefficient to encourage exploration
model = PPO(
    "MlpPolicy",
    env,
    ent_coef=0.1,   # Increase from default 0.0
    learning_rate=3e-4,
)

# Or, use a schedule to decay entropy over time
from stable_baselines3.common.callbacks import EvalCallback
model = PPO(
    "MlpPolicy",
    env,
    ent_coef=0.05,
    policy_kwargs={"net_arch": [128, 128]},  # Larger network = more exploration needed
)


Verhaltens- & Belohnungs-Debugging

TensorBoard-Belohnung steigt, aber Agent wirkt in Godot falsch

Ursache: Die Belohnung passt nicht zum gewünschten Verhalten. Der Agent maximiert die Zahl, ohne die Aufgabe zu lösen (Reward Hacking).

Fix:

// Example: agent may "cheat" by moving quickly rather than reaching the goal
// BAD: only reward for velocity
float reward = velocity.Length() * 0.1f;

// BETTER: reward progress toward goal AND reaching goal
float distance_to_goal = Vector2.Distance(transform.GlobalPosition, goal.GlobalPosition);
float reward = -distance_to_goal * 0.1f;  // Progress penalty
if (distance_to_goal < 1.0f) {
    reward += 1.0f;  // Goal bonus
}

Den Agenten während des Trainings in Godot beobachten und mit der TensorBoard-Kurve vergleichen. Sie sollten geistig zusammenpassen.


Agent ignoriert Hindernisse / Ziele, die sichtbar sind

Ursache: Die Beobachtung enthält oder aktualisiert keine Infos zu Hindernissen/Zielen, oder Beobachtungen sind gecached und werden nicht pro Schritt aktualisiert.

Fix:

// In AIController: ensure observations are updated every frame
public override Dictionary<string, object> GetObservation() {
    // Observations MUST be recomputed each call, not cached
    var obs = new float[] {
        transform.GlobalPosition.X,
        transform.GlobalPosition.Y,
        target.GlobalPosition.X,
        target.GlobalPosition.Y,
        // ... include obstacle positions
    };
    return new Dictionary<string, object> { { "obs", obs } };
}

// Call in _PhysicsProcess, not _Process (to stay in sync with physics)
public override void _PhysicsProcess(float delta) {
    var obs = GetObservation();
    // Reset position next frame if goal reached
}


Agent nutzt die Belohnung aus, statt die Aufgabe zu lösen

Ursache: Reward Hacking — der Agent fand einen Weg, die Zahl zu maximieren, ohne das Ziel zu erreichen.

Fix:

// Example: agent may stay in place and get stuck if you only reward reaching goal
// Add a small step cost to push the agent forward
float reward = -0.01f;  // Step penalty

// Penalize if agent gets stuck
if (stuck_timer > max_stuck_time) {
    reward -= 0.5f;
}

// Reward goal
if (distance < goal_radius) {
    reward += 1.0f;
}

return reward;

Manuell prüfen, dass die höchstbelohnten Aktionen deiner Intuition entsprechen.


rollout/ep_len_mean ist immer max_episode_steps (Ziel nie erreicht)

Ursache: Die done-Bedingung wird nie ausgelöst — entweder erreicht der Agent nie Erfolg, oder du gibst kein done=True zurück.

Fix:

// In AIController: check and return done
public override bool IsDone() {
    // Done when goal is reached
    bool goal_reached = Vector2.Distance(transform.GlobalPosition, goal.GlobalPosition) < 1.0f;

    // Or when out of bounds
    bool out_of_bounds = transform.GlobalPosition.Length() > max_distance;

    // Or when max steps exceeded (framework handles this, but you can override)
    bool timeout = step_count >= max_steps;

    return goal_reached || out_of_bounds || timeout;
}

Per Print debuggen:

# In Python
done_reasons = {"goal": 0, "timeout": 0, "oob": 0}
for episode in range(100):
    obs, info = env.reset()
    while True:
        action, _ = model.predict(obs)
        obs, reward, terminated, truncated, info = env.step(action)
        done = terminated or truncated
        if done:
            if info.get("goal_reached"):
                done_reasons["goal"] += 1
            else:
                done_reasons["timeout"] += 1
            break
print(done_reasons)


ONNX-Export & Deployment

ONNX-Export gelingt, aber Godot-Inferenz produziert Müll-Aktionen

Ursache: Der ONNX-Export enthielt das Tanh-Squashing am Ausgang nicht, oder der Actor wurde ohne den Log-Std-Layer (SAC) exportiert.

Fix:

# For PPO, export the full policy (includes tanh output layer)
model.policy.actor.to("cpu")
model.policy.actor.eval()

# Use the stable_baselines3 export utility
from stable_baselines3.common.policies import BasePolicy
input_dict = {"obs": np.zeros((1, obs_space.shape[0]), dtype=np.float32)}
model.policy.actor.to("cpu")

# Export with opset 11 or 15 to ensure compatibility
import onnx
onnx_model, _ = convert_pytorch(model.policy.actor, input_dict, opset_version=11)
onnx.save(onnx_model, "policy.onnx")

Vor dem Godot-Deployment in Python testen:

import onnxruntime as ort
sess = ort.InferenceSession("policy.onnx")
action = sess.run(None, {"obs": obs})
print(action[0].shape, action[0].min(), action[0].max())  # Should be [-1, 1] for tanh


ONNX-Modell in Godot liefert falsche Tensor-Form

Ursache: input_names/output_names passen nicht zum exportierten Modell, oder die Reihenfolge ist vertauscht.

Fix:

// In Godot C#, when loading ONNX:
var model = new OnnxModel();
model.LoadModel("res://policy.onnx");

// Get the input/output node names from the exported model
// Use a tool like Netron to inspect the ONNX file:
// - Input node: "obs" (float32, shape [1, n_obs])
// - Output node: "output_0" (float32, shape [1, n_actions])

var input_dict = new Dictionary<string, Tensor> {
    { "obs", Tensor.FromArray<float>(obs_array) }
};
var outputs = model.Run(input_dict);
var actions = outputs["output_0"];  // or "output_name" from your export

ONNX-Datei mit Netron (netron.app) prüfen, um Knotennamen und Formen zu verifizieren.


ONNX-Inferenz in Godot ist langsam

Ursache: Modell zu groß (z. B. CNN-Policy für visuelle Obs) oder GPU-inkompatibler Runtime.

Fix:

# Use MlpPolicy for real-time inference, not CnnPolicy
model = PPO("MlpPolicy", env, ...)  # Good for real-time
# Avoid: PPO("CnnPolicy", env, ...)  # Slow in game engine

# For visual observations, either:
# 1. Train with CnnPolicy in Python, then distill to MlpPolicy
# 2. Use very small image sizes (e.g., 32x32 instead of 84x84)

Typische Inferenzzeit: MlpPolicy in Godot 1–5 ms. CnnPolicy 50–200 ms.


onnxruntime.InvalidGraph: Load model from ... failed

Ursache: ONNX-Opset-Version inkompatibel mit deinem onnxruntime, oder das Modell wurde nicht korrekt exportiert.

Fix:

# Export with opset version 11 or 15 (both widely supported)
from stable_baselines3.common.policies import BasePolicy
# When exporting, specify opset_version=11

# Or, update your onnxruntime
pip install --upgrade onnxruntime

Auch prüfen, dass die ONNX-Datei gültig ist:

python -c "import onnx; model = onnx.load('policy.onnx'); onnx.checker.check_model(model); print('Valid')"


Immer noch festhängen?

Wenn dein Problem hier nicht steht, prüfe:

  1. GitHub Issues — nach deiner Fehlermeldung im godot-rl-agents-Repo suchen.
  2. Godot-Docs — für Godot-spezifische Fehler (Physik, Signale etc.).
  3. SB3-Docs — für SB3-Algorithmen und Hyperparameter.
  4. Kurs-Units — jede Unit hat detaillierte Beispiele und eigene Troubleshooting-Abschnitte.
  5. Logging & Debugging — Print-Statements in Godot und Python; TensorBoard zur Visualisierung.

Vor dem Öffnen eines Issues bitte angeben: - Deine Python-Version (python --version) - Deine Godot-Version - Die exakte Fehlermeldung (volles Traceback) - Dein Trainings-Skript (gesäubert) - Ein minimal reproduzierbares Beispiel (wenn möglich)