GDExtension fails to load on newer Godot 4.x minor release
0 reputation · 17 Aug 2021, 17:59 UTC
0 reputation · 17 Aug 2021, 17:59 UTC
The goal is to determine why a GDExtension binary compiled against one Godot 4 minor release (e.g., 4.1) refuses to initialize when opened in a later release (e.g., 4.2 or 4.3). The engine performs a runtime check against the extension_api.json that accompanies each release; if the binary was built with a different API dump, the editor or export may emit a “not compatible” warning or silently skip registration.
Constraints include the fact that Godot 4 minor updates can introduce new or removed symbols in the extension API, and that godot-cpp bindings are pinned to a specific commit per engine version. A single binary cannot guarantee backward or forward compatibility across these changes.
Unresolved decision: should a project ship a separate GDExtension binary for each supported minor release, or restrict the entire codebase to a single pinned engine version to avoid runtime failures?
35775 reputation · 17 Aug 2021, 18:09 UTC
GDExtension does not guarantee a stable ABI across Godot 4.x minor releases. A binary compiled against 4.1's API dump is only safe to load in 4.1; opening it in 4.2 or 4.3 risks a refused load or, worse, subtle crashes. The reliable fix is to recompile the extension against the godot-cpp bindings and extension_api.json matching each engine version you intend to support — which means shipping one binary per minor release, or pinning your project to a single engine version.
Each Godot release ships an extension_api.json describing the exact class layout, method signatures, and enum values the engine exposes. godot-cpp generates bindings from that dump, and your compiled binary bakes in assumptions from it: method hashes, struct sizes, and virtual call offsets. When a minor release adds, removes, or reorders API entries, those baked-in assumptions no longer match the running engine. Godot performs a compatibility check at load time and refuses to initialize the extension — or, in edge cases where the check passes but layouts shifted, you get undefined behavior at runtime.
This is a deliberate design trade-off: GDExtension targets a stable API within a minor release line (patch releases like 4.2.1 → 4.2.2 are compatible), not across minor boundaries.
GDExtension errors such as "not compatible with the current engine version" or a failure to retrieve the initialization function.--verbose.extension_api.json your godot-cpp checkout was generated from against the one in the target engine's release — any diff in the dump is a rebuild trigger.Verify your build alignment first:
cd godot-cpp && git log -1 --oneline
# Confirm this commit/tag matches your target engine branch (e.g. godot-4.3-stable)For a library distributed to other users (e.g., via the Asset Library), per-minor-release binaries are the sustainable choice: build a matrix (4.1, 4.2, 4.3) in CI, each against the matching godot-cpp tag, and name artifacts by version. Users pick the binary for their engine.
For an in-house game where you control the engine version, pinning is simpler and cheaper: lock the whole team and your export templates to one minor release, and upgrade engine + extension together as a single atomic change.
Exact error wording and the strictness of the load-time check vary between releases, so treat the diagnostic strings above as indicative rather than verbatim — confirm against your specific engine version's console output. The core behavior (rebuild per minor release) is well established; version-specific check details are worth verifying before automating around them.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.