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

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