stride3d/stride · error · FileNotFoundException
Could not locate native library
Error message
Could not locate native library ${libraryName} What it means
LocateLibrary throws FileNotFoundException when a native library (name plus the platform extension .dll/.so/.dylib, including 'lib'-prefixed and SONAME-versioned variants on Unix) cannot be found in the packaged native-dependency cache or under the owner assembly's runtimes/{platform}-{cpu}/native folder. It indicates the native dependency required for P/Invoke is absent from the deployment.
Solutions
- Confirm the native library for the current RID exists next to the owner assembly (runtimes/{rid}/native/libname.so / name.dll / libname.dylib).
- Ensure the NuGet package ships native assets for all target RIDs or install the matching runtime pack.
- On Linux/macOS, verify SONAME-versioned files are present (e.g. libassimp.so.5) since the helper globs variants but needs at least one to exist.
- Catch FileNotFoundException and either load from a user-configured path via NativeLibrary.Load or produce an install instruction message.
- Check the library name spelling/casing and whether the 'lib' prefix convention is met.
Example fix
// before
var path = NativeLibraryHelper.LocateLibrary("assimp", typeof(App)); // FileNotFoundException on slim publish
// after
string path;
try { path = NativeLibraryHelper.LocateLibrary("assimp", typeof(App)); }
catch (FileNotFoundException ex)
{
throw new InvalidOperationException(
"Native library 'assimp' missing. Ensure the Stride native assets package for " +
$"{RuntimeInformation.RuntimeIdentifier} is referenced.", ex);
} Defensive patterns
Strategy: try-catch
Validate before calling
static bool NativeLibPresent(string lib, Type owner)
{
var ext = OperatingSystem.IsWindows() ? ".dll" : OperatingSystem.IsMacOS() ? ".dylib" : ".so";
var rid = RuntimeInformation.RuntimeIdentifier;
var dir = Path.Combine(AppContext.BaseDirectory, "runtimes", rid, "native");
return File.Exists(Path.Combine(dir, lib + ext)) || File.Exists(Path.Combine(dir, "lib" + lib + ext));
} Try / catch
try
{
libPath = NativeLibraryHelper.LocateLibrary(libraryName, ownerType);
}
catch (FileNotFoundException ex)
{
throw new InvalidOperationException(
$"Native library '{libraryName}' not found for {RuntimeInformation.RuntimeIdentifier}. Install the matching native assets package.", ex);
} Prevention
- Ensure native runtimes assets are included in publish (don't strip runtimes/ folder).
- Keep SONAME-versioned files (libfoo.so.N) alongside the .so on Unix.
- Match library names/casing against package contents; remember the automatic 'lib' prefix attempt on Unix.
- Add per-RID integration tests that call LocateLibrary for every native dependency.
When it happens
Trigger: Calling NativeLibraryHelper.LocateLibrary(libraryName, ownerType) where neither 'libraryName.ext' nor, on non-Windows, 'liblibraryName.ext' (nor SONAME-versioned variants) exists next to the owner assembly or in its runtimes-specific native folder.
Common situations: Linux deployment where the .so was not packaged for linux-x64; library renamed or version-bumped (libfoo.so.6 vs libfoo.so.7 mismatch); self-contained publish that trimmed native assets; running tests from a directory lacking the runtimes layout; package depends on a system library the user hasn't installed.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Could not locate native executable
- Bundle could not be resolved
- Could not find executable to start assembly
- Package file [ ] was not found
- Metadata loaded from nuspec cannot have more than one group…
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/0c0a300d568b3b73.
Report an issue: GitHub.
Appendix: source
Thrown at sources/core/Stride.Core/Native/NativeLibraryHelper.cs:156
{
var nameWithExtension = name + libExtension;
// Resolver-registered natives: the extension-less map is keyed by SONAME-stripped base name
// (matches libassimp.so.6); the with-extension map only matches an exact unversioned filename.
if (nativeDependenciesWithoutExtensions.TryGetValue(name, out string? knownPath)
|| nativeDependenciesWithExtensions.TryGetValue(nameWithExtension, out knownPath))
return knownPath;
// Try in current path
if (File.Exists(nameWithExtension))
return nameWithExtension;
// Try runtimes specific path (globs SONAME-versioned variants, picks highest)
if (TryFindLibraryPath(ownerType, nameWithExtension, out knownPath))
return knownPath;
}
throw new FileNotFoundException($"Could not locate native library {libraryName}");
}
/// <summary>
/// Preloads a native library (or returns the handle of one already loaded), so subsequent P/Invoke
/// calls use it instead of triggering their own load. The returned OS module handle also lets callers
/// that resolve exports themselves (for example, libraries with their own function-pointer binding)
/// share the engine's native resolution.
/// </summary>
/// <param name="libraryName">The name of the library, without the extension.</param>
/// <param name="ownerType">
/// The <see cref="Type"/> whose Assembly location is related to the native library.
/// This is needed because <see cref="Assembly.GetCallingAssembly"/> cannot be used,
/// as it might be wrong due to optimizations.
/// </param>
/// <returns>The OS module handle of the loaded library.</returns>
/// <exception cref="DllNotFoundException">
/// The library with name <paramref name="libraryName"/> could not be loaded.
/// </exception>View on GitHub (pinned to 96fad776d2)