Skip to content

macOS: the documented godot symlink makes every headless call hang forever #43

Description

@zjoooooo

What happens

Following setup.md's macOS instructions produces a godot that hangs forever on every headless invocation — --headless --import, --headless --quit, any build gate. The process sits at ~0% CPU and never returns. Nothing on stdout past .NET: Initializing module....

Repro

brew install --cask godot-mono
sudo ln -sf /Applications/Godot_mono.app/Contents/MacOS/Godot /usr/local/bin/godot   # setup.md:114
cd <any godot project>
godot --headless --quit    # never returns

Cause

Two things compounding:

1. Godot resolves GodotSharp/ relative to the path it was invoked as. Through the symlink it looks in /usr/local/bin/, finds nothing, and raises a fatal error. setup.md:108 already states the rule — "GodotSharp/ must live next to the godot binary. Godot resolves it relative to itself." — and the macOS command two lines below violates it, since the bundle keeps GodotSharp/ in Contents/Resources/ while the symlink points at Contents/MacOS/Godot.

2. On macOS that fatal error is an NSAlert modal, and --headless has no window to dismiss it. sample on the stuck process:

2577 Thread_8627957: Main Thread   DispatchQueue_<multiple>
  2457 -[NSAlert runModal]  (in AppKit) + 196
    2433 _NSTryRunModal  (in AppKit) + 100
      2428 -[NSApplication runModalForWindow:]  (in AppKit) + 292
        2406 -[NSApplication _doModalLoop:peek:]  (in AppKit) + 216

So the failure mode is an indefinite hang rather than an error exit. For an unattended run that is the worst possible shape — the process sits all night at zero CPU with nothing to react to. This applies to any fatal error on macOS, not just this one: a project with no main scene prints Can't run project: no main scene defined and then hangs on the same modal.

Fix

A wrapper script instead of the symlink, plus the trap and its handling in engines/godot.md: wrap every godot call in timeout, treat exit 124 as the failure signal.

Two capture facts confirmed while verifying, also worth recording in the engine guide: on macOS the backend is Metal and there is no xvfb, and --write-movie combined with --headless aborts (Parameter "t" is null, exit 134) — capture has to run windowed.

Verified on

macOS 26.5.2 (Apple M5), Godot 4.7.1.stable.mono, .NET SDK 10.0.302. Full chain green after the fix: dotnet build → build-time SceneTree scene generation (26/26 nodes, pack-validated) → --headless --import--headless --quit--write-movie 450 frames → ffmpeg mp4.

Branch with the fix: https://github.com/zjoooooo/godogen/tree/macos-headless-traps

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions