Troubleshooting
Each section gives a symptom, its causes, how to tell which cause you have, and the fix. The messages quoted are the exact text the engine writes or throws. Most of them reach you only when logging is set up, so start with the first section if nothing shows.
No messages appear in the log
The game and the server log through Microsoft.Extensions.Logging. A game with no logging provider
writes nothing, so none of the messages on this page can be seen. Register one in Configure, as
Setting up a project shows. A server has a console provider already, at
Information and above (see Logging).
Some messages are at Debug or Trace level. To see every message on this page, set the minimum level
to LogLevel.Trace.
The game starts on OpenGL with a Vulkan error, or stops with one
Vulkan is the default renderer. When it cannot start, the game logs a warning with the reason, and starts on OpenGL instead:
The Vulkan render backend failed to start: <reason>. Starting on the OpenGL render backend instead.
The reason is one of these messages, which says what is missing:
SDL_Vulkan_LoadLibrary failed: <SDL error>. Ensure Vulkan loader/runtime is installed.The Vulkan loader is not installed. On Linux, install the distribution's Vulkan loader package.No Vulkan physical devices were found.The loader is there, but no driver for a GPU is. Install the Vulkan driver for the graphics hardware, such as Mesa's Vulkan drivers on Linux. A virtual machine without GPU access usually has none.No Vulkan physical device supports graphics + present for the SDL surface.A GPU has Vulkan, but none of its devices can draw to this window.vkCreateInstance failed with <result>.The library found cannot start a Vulkan instance. On a Mac, see The game will not start on a Mac.
Install the missing part to run on Vulkan. Until then the game runs on OpenGL, whose name is set with
--render-backend opengl on the command line, with the BSGAMELIB_RENDER_BACKEND environment variable,
or with PreferredRenderBackend in the game's WindowOptions. See
Render backends.
With the fallback turned off, the game stops at startup instead. The exception's message begins with
The Vulkan render backend failed to start: followed by the same reason, and says that starting on
OpenGL is turned off. Turn it off with AllowRenderBackendFallback = false in the game's WindowOptions,
or with BSGAMELIB_RENDER_BACKEND_FALLBACK=0. See
Falling back to OpenGL.
The game runs on a different renderer from the one I set
The log says which renderer was chosen, and why. Look for one of these, at Information level:
Using OpenGL render backend requested via environment variable BSGAMELIB_RENDER_BACKEND ('opengl').Using Vulkan render backend requested via command line option ('vk').Using default Vulkan render backend.
The renderer is taken from the first of these that is set: the environment variable, then the command
line, then PreferredRenderBackend, then Vulkan. An environment variable or argument set in the
shell therefore overrides the game's own choice. Unset it, or pass the name you want.
If Vulkan was chosen and failed to start, the log has the Vulkan warning instead, and the game runs on OpenGL. See The game starts on OpenGL with a Vulkan error.
A name the engine does not know is ignored, with this warning:
Requested render backend 'metal' via command line option is not available. Falling back to Vulkan.
The names are vulkan, vk or default for Vulkan, and opengl, open-gl or gl for OpenGL.
The game will not start on a Mac
The Vulkan renderer on macOS uses MoltenVK, which the package copies beside the game when it is
published for osx-arm64 or osx-x64 (see Platforms). The messages are:
SDL failed to load Vulkan library (initial error: <SDL error>). Install the Vulkan/MoltenVK runtime and ensure libvulkan or libMoltenVK is on your library path.The game did not findlibMoltenVK.dylibbeside its executable, nor in/usr/local/libor/opt/homebrew/lib. This happens when the game is run from a copy that lacks the library, such as a hand-made folder, or from a build that was not published for a Mac runtime. Publish forosx-arm64orosx-x64, or install MoltenVK in one of those folders.vkCreateInstance failed with ErrorIncompatibleDriver.The library that was found cannot start a Vulkan instance. Publish again for the Mac's runtime, so the game's folder gets the library for that platform.
Without MoltenVK the game starts on OpenGL, with the warning above in the log. See Render backends.
The build fails with "bsshaderc was not found"
The build error is bsshaderc was not found, so shaders cannot be precompiled. Set BSGameLibShaderCompilerPath to bsshaderc.dll. It appears only in a project with BSGameLibShader
or BSGameLibRawShader items. The compiler is in the package's tools folder. The error means that
folder has no compiler, which happens when the package is damaged or when the engine is referenced as a
project, with no shader build project beside it.
Restore the packages again, with dotnet restore --force. If that does not help, set
BSGameLibShaderCompilerPath in the project to the path of a built bsshaderc.dll. See
Shaders.
A shader cannot be compiled for Vulkan at run time
The Vulkan renderer logs this warning once for each shader it cannot compile:
A Fragment shader (<key>) could not be compiled for Vulkan. A sprite or shape material that uses it is drawn by the built-in pipeline without its shader; a full-screen effect that uses it throws when it is created.
The warning is logged once per shader. A sprite or shape that uses the shader still appears, without the shader's effect. A full-screen effect that uses it is not created. The line after the warning gives the reason. When the game has no runtime compiler, it is:
No precompiled SPIR-V matches this Fragment shader (<key>), and no runtime shader compiler is registered. Precompile it at build with a BSGameLibShader item, or register one with AddShaderCompiler() from BSGameLib.Game.ShaderCompiler.
Two causes give this message:
- The shader is read from a file, downloaded or generated, so the build never compiled it.
- A runtime compiler is registered, and the GLSL does not compile. The compiler's diagnostics follow the warning.
A full-screen effect whose shader fails is not created. Creating it throws The shader could not be compiled for Vulkan. with the same diagnostics.
The fix is to add the shader to the project as a BSGameLibShader item, so the build compiles it. For
shaders that only exist at run time, add the BSGameLib.Game.ShaderCompiler package and call
AddShaderCompiler(). Both are described in Shaders. Fix the GLSL if the
compiler reports an error in it.
Text in the game's own fonts is blank
Blank text in the game's fonts is not logged. There are two causes:
- The font has no glyph for that character. The text is drawn with a gap where the character should be.
- A TrueType font draws only characters up to U+FFFF. Most emoji, and some rare Chinese characters, are above that, so they are blank in a TrueType font whatever the font contains.
To tell them apart, open the font in a font viewer and look for the character. If it is there and above U+FFFF, the second cause applies. If it is not there, use a font that has it, and for a BMFont generate the file with that character included. See Content.
A font file is not found, and text is missing or the view fails
When the font file is not where the game looks, GetBMFont and GetTrueTypeFont return null and
log a warning at Warning level, with the full path they looked at:
BMFont <file> not found at <path>, returning null, or TrueTypeFont <file> not found at <path>, returning null. What happens next depends on the label:
- A
Labelwith aFontSizedraws nothing. The warning above is the only sign. - A
Labelwith noFontSizefails to build the view withCould not find font <file> for label <id>. Please make sure the file exists and is a valid font file. - Drawing with a missing font directly, outside a view, throws
Value cannot be null. (Parameter 'font').
Font files are looked up under the content root. The causes are:
- The path is wrong. A view's
Fontis a path relative to the content root. - The file is not copied to the output folder. Add it as a
Contentitem withCopyToOutputDirectory. - The root is not the game's folder. The root is the working directory until the game sets it, so set
it to
AppContext.BaseDirectory. See Content.
On Linux a name in a path need not match its case, folder names included. See Content.
A font loads, but a view fails with "Could not load font"
The .fnt file is found, but one of the page images it names is not. The log then has an error,
Error loading font <font file> for label <id>, with the real cause as its inner exception: Could not find file '<path>'. The view then fails with this message:
Could not load font <font file> for label <id>. Please make sure it is a valid font file.
The message does not name the page image, so read the inner exception. Copy the page images to the
output folder, beside the .fnt file. The page names inside the .fnt file are relative to that
folder. See Content.
Text in Japanese, Russian or another script is blank in Dear ImGui windows
Dear ImGui's built-in font has Latin letters only. The game's own text is not affected, so the symptom is only in ImGui windows.
If the font file you pass to UseFont does not exist, the log says
ImGui font '<path>' does not exist; keeping the built-in font. Otherwise the cause is the missing
script. Merge in a font that has the script's glyphs, with the matching constant from
LanguageScripts: Japanese, Cyrillic and so on. See Dear ImGui.
Localized text shows the key instead of the words
These warnings explain it:
Localization key not found: <key>means the key is not in the language being looked up, and the text shows the key instead. Check the key's spelling, and that the language file has it.Localization folder '<path>' does not exist; no languages discovered.means the folder thatFilePathnames is not there. Its default,Localization, is relative to the working directory, not the game's folder. SetFilePathto a path underAppContext.BaseDirectory, and copy the files into the output.Localization file not found for language code '<code>' at path '<path>'.means a language was added, but its file is not in the folder.
If the default language and the fallback both fail to load, InitializeLanguages throws
Default language '<code>' was not loaded successfully. Its fix is the same. The
Problems list on LocalizationBootstrap names what is wrong with each file. See
Localization.
A sound does not play
The log warns about the asset:
Audio asset '<asset>' for event '<event>' was not found.
Asset paths are looked up beside the executable first, then in the working directory. The content root does not apply to sounds. Copy the file into the output folder. Posting an event that was never registered also logs a warning. See Audio.
Packets from the other side are refused
The adapter logs Error handling packet from server. on a client, or Error handling packet from <IP address>. on a server, with an ArgumentOutOfRangeException whose message is:
Packet with hash <hash> is not recognized.
The receiving side does not know the packet type. A packet is identified by its class name, so this usually means the two builds have different packet classes: one side is an older build, or a class was renamed on one side only. Build the client and the server from the same packet classes. See Packets.
A packet arrives, and nothing happens
At Debug level the log shows the arrival, with the number of handlers that ran:
Packet of type <type> received. 0 handlers were run.
Nothing is logged as an error, because a registered packet with no handler is dropped. The cause is that
no handler is registered for that packet type on the receiving side. The handler class is missing, or it
is marked DoNotRegister. See Registering packets and handlers
and Leaving a type out.
Two packet classes have the same name
The server stops at startup with an InvalidOperationException whose message is this, with the full
names of the classes that clash:
Packet types must have distinct short names, since a packet is identified on the wire by a hash of its short name, so two would share one id. Short names shared: "<name>": <full name> and <full name>. Rename one of each pair.
A client that registers its packets itself gets the same message at RegisterPacket, or when it makes
its DataPacketManager. Packets are identified by their class name, not by namespace, so rename one of
them. See Packet identity.
Game state changes unpredictably when packets arrive
Packet handlers run on the networking threads, not on the game's thread. A handler that changes state the game reads every frame races with the game loop. The result is usually an intermittent crash, or a state that is half changed, and no error from the handler itself.
In a client, set HandlerRunner so that the handlers are posted to the game's IGameThread. On a
server, set it in an IInitializer, or take a lock in the handlers and in Update. See
Handlers and threads and
Packet handlers and the loop.
The client cannot connect to the server
The client throws an IOException:
Could not connect to <address>:<port>: the connection was refused or could not be made.
The causes are that the server is not running, that the address or port is wrong, or that a firewall
blocks UDP. The server uses two UDP ports: ListenPort, 55237 by default, and ListenPort plus 2.
Open both. If the server's BindAddress is a loopback address such as 127.0.0.1, only clients on the
server's own machine can reach it. See Ports and
Firewalls.
The server does not start on Linux or macOS
The server logs Error starting game socket. at Critical level, followed by this exception:
PlatformNotSupportedException: QUIC is not available because the msquic native library is missing.
The rest of the message says where msquic comes from. The BSGameLib.MsQuic.Native package supplies
it for Linux (x64 and arm64) and for Apple silicon, and a self-contained publish loads the copy beside
the game. A framework-dependent run, such as dotnet run, uses an msquic installed on the system, not the copy beside the game. So
either publish self-contained, with --self-contained, or install msquic from your system's packages
(libmsquic on Linux). On an Intel Mac there is no bundled library, so install msquic there too. See
Platforms and Platforms.
The server stops at startup because it has no certificate
The server logs Error starting game socket. and then this exception:
NetworkAdapterConfiguration.Quic.ServerCertificate is required.
This happens when QuicConfiguration is set without a ServerCertificate. Either set the certificate,
or leave QuicConfiguration unset, so the server makes its own development certificate. See
The host and its settings and
Making a server certificate.
The server does not start because its port is in use
The server logs Error starting game socket. at Critical level. The exception beneath it is the
operating system's socket error. The usual cause is another process using ListenPort or
ListenPort plus 2, on UDP. Stop that process, or change ListenPort in the server's settings. See
The host and its settings.
The server stops at startup and names BindAddress
The server stops with an InvalidOperationException whose message is one of these:
BindAddress "<value>" is not an IP address. Use an address such as "127.0.0.1" or "::1", or leave BindAddress unset to listen on every address. A host name is not looked up.
BindAddress "<value>" is an IPv6 address, and this host has no IPv6.
BindAddress takes an IP address literal, not a host name. Use one of those, or leave it unset to
listen on every address. See The host and its settings.
Clients refuse the server after its certificate changed
A client logs a warning with this start:
QUIC server identity mismatch for <address>:<port>: expected fingerprint <A>, but the server presented <B>.
The warning ends with Rejecting connection. Clients remember the certificate that a server first
presented, in quic-server-pins.json in the folder of the client's executable. A server with a
different certificate is refused until that record is removed. The usual causes are that the server's
certificate file was deleted, that a new certificate was installed, or that another machine answers at
that address.
If the change is intended, delete that server's entry from quic-server-pins.json on the client, and
the next connection records the new certificate. If it was not intended, restore the server's
certificate. See Trust on first use.
The log says certificate validation was bypassed
Every connection logs this warning:
QUIC certificate validation bypassed (AllowUntrustedCertificates=true) for <server>. This connection is encrypted but NOT authenticated.
The client has AllowUntrustedCertificates set, so it does not check the server's identity at all. It
is for development only. Remove it before the game is released. See
Development: skip the check.
The server stops and names IGameServer as required
The server stops at startup with this exception:
Fatal exception. The following types are required to be implemented: followed by
BSGameLib.Server.IGameServer.
No class implementing IGameServer was found. Write one, in an assembly the host scans. See
The game loop and
What is scanned.
The server stops with "Sequence contains more than one element"
The host needs exactly one class that implements IGameServer, and this is the exception when there are
two. The message does not name the classes. Search the project for : IGameServer to find both, and
keep one. See How it finds your code.
The server keeps running, but the world stops updating
When Update throws, the tick is skipped and the loop carries on. The first failure is logged as an
error with its exception:
A game tick failed and was skipped (<n> so far). The game loop carries on.
Read the exception logged with the first failure, which says where Update threw. Later failures are
logged at most once every five seconds. See Failing ticks.
A view does not open
Opening a view throws when the view is not valid. The exception is an AggregateException out of
SetView, PushView or ShowPanel. Its InnerExceptions are the validation errors, such as a
Button with no Size, or a ComboBox with no options. A GridLayout cell outside the grid throws
an ArgumentOutOfRangeException as the view is built. If a binding cannot be set up, the log says
Error setting up bindings for view <view>.
To find these before the game runs, check the view files with ViewFileValidator. See
Checking views before they run.
A binding is skipped, and the control shows its default
The log warns once for each binding it skips:
Binding <Control>.<Property> to "<Key>" was skipped: <problem>.
The problem is one of the view model has no readable property with that name, the view model has no writable property with that name, or a value that cannot be converted, such as the value '<value>' cannot be read as <Type>. Check the name against the view-model's property, including its case. See
When a name does not match.
The server fails to start with "attempted to register an existing keyword"
Two chat commands share a keyword. The message is:
"<command>" attempted to register an existing keyword '<keyword>' for "<other command>", .
Give one of the commands a different keyword with WithKeywords, or with the [Command] attribute's
keywords. See Commands.