Skip to content

Surface dlerror/GetLastError reason on Loader load failure#843

Open
danlniel wants to merge 1 commit into
jpsim:mainfrom
danlniel:improve-loader-failure-diagnostics
Open

Surface dlerror/GetLastError reason on Loader load failure#843
danlniel wants to merge 1 commit into
jpsim:mainfrom
danlniel:improve-loader-failure-diagnostics

Conversation

@danlniel

Copy link
Copy Markdown

Summary

Today, when Loader.load(path:) cannot dlopen sourcekitdInProc it traps with the bare message Loading <path> failed. That message discards the actual OS error and forces downstream users (SwiftLint, jazzy, sourcekitten itself) to guess at the root cause. Users hitting this — e.g. realm/SwiftLint#6475 — end up chasing red herrings (sandboxing, Xcode versions, mise pinning) before the actual cause is found.

This PR collects dlerror() (POSIX) / GetLastError() (Windows) for every candidate path attempted, and includes them in the fatalError message. Successful-load paths are unchanged.

Why it matters

The motivating case is Xcode 26 shipping sourcekitdInProc.framework as arm64-only. When SwiftLint is invoked from an x86_64-rooted process tree (e.g. an x86_64 Ruby running fastlane on an Apple Silicon machine), the universal SwiftLint binary launches x86_64 to match its parent, and dlopen fails with:

mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64')

Before this PR users see Loading sourcekitdInProc.framework/Versions/A/sourcekitdInProc failed and have no idea what to do. After this PR they see the actual reason and can immediately rebuild Ruby as arm64 (or run through arch -arm64) instead.

Changes

  • Loader.load collects per-attempt errors and feeds them into a new Loader.failureMessage(path:attemptFailures:) helper.
  • The helper is static so it can be tested without triggering fatalError.
  • New LoaderTests covers both the populated-attempts path and the empty-attempts edge case.
  • CHANGELOG.md entry under a new ## Main section.

Test plan

  • swift build — clean
  • swift test --filter LoaderTests — 2/2 pass
  • Full swift test — no new failures (6 pre-existing SourceKitTests failures are Swift-toolchain-version drift on Xcode 26.4, unrelated to this change)
  • Manually verified the new message format reads well with real dyld errors

Refs realm/SwiftLint#6475

When the Darwin/Linux/Windows loaders fail to dlopen sourcekitdInProc
(or libsourcekitdInProc.so / sourcekitdInProc.dll), they currently
discard the underlying error and trap with the bare message
"Loading X failed". That message tells the user nothing actionable,
and the failure has many possible root causes (toolchain not found,
architecture mismatch when running through Rosetta, permission, etc).

Capture each candidate path that was tried and the OS-reported reason
(dlerror() on POSIX, GetLastError() on Windows), and include the full
list in the fatalError message. The successful-load path is unchanged.

This is the kind of failure SwiftLint users have been hitting on
Xcode 26+ when a SwiftLint build phase ends up running through an
x86_64 build chain (e.g. an x86_64 ruby / fastlane host) while
Xcode 26 ships sourcekitdInProc.framework as arm64-only. Today they
get the bare "Loading X failed" trap; after this change they'd see
"mach-o file, but is an incompatible architecture (have 'arm64',
need 'x86_64')" pointing straight at the cause.

Refs realm/SwiftLint#6475
@johnfairh

Copy link
Copy Markdown
Collaborator

Thanks for the PR - looks good. I think it's OK to not go any further to decode the windows error given the state of support there.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants