Troubleshooting
Sorry if things are going wrong!
Contents
Update clangd
Every release fixes many bugs, works in more scenarios, and provides clearer logs for troubleshooting.
Try to install the latest major-version release or even a pre-release snapshot before you try anything else!
Gathering logs
Your editor should make clangd’s stderr
log available (see installation
for how). These describe the messages exchanged between the editor and clangd
,
and what clangd was thinking.
Even if you don’t understand the contents, it’s tremendously useful to include
this when filing a bug. If you add --log=verbose
to the clangd arguments, this
will include more detail (e.g. the full content of LSP messages).
Lots of error diagnostics
If your code builds OK but clangd shows lots of error diagnostics, it probably can’t parse your code very well. Other features will work poorly too:
Can’t find includes within your project
This usually means that we don’t have a compile command for this file.
compile_commands.json
should exist in some parent directory and should have
a valid command. If this file has changed, you’ll need to restart clangd to see
the changes.
The logs can tell you whether compile_commands.json
was found and what compile
command was ultimately used.
Can’t find standard library headers (<map>
, <stdio.h>
etc)
First, you’ll need the standard library (and any other libraries you depend on) installed on your system! Even if you don’t actually build on this machine, clangd needs to parse the headers.
The standard library headers are often found relative to the compiler.
Try to configure your project with an absolute path to the compiler
(/usr/bin/gcc
, not gcc
).
The logs (with --log=verbose
) can tell you the cc1
command, including which
paths were searched for the standard library. You can compare this to the output
of clang -### <args>
.
If you’re using an unusual compiler (e.g. a cross-compiler for a different
platform, or MinGW on Windows) you may want to pass --query-driver=/path/to/mygcc
or --query-driver=/path/to/mygcc,/path/to/myg++
when using C++ to allow clangd
to extract the include paths from it directly.
It is recommended to use --query-driver
over specifying system include paths
manually using configuration files as getting the latter right
can be tricky (the order of include paths are important, for instance).
Generally the value of --query-driver
should match the command emitted by
your build system in compile_commands.json
, such as /usr/bin/c++
.
Can’t find compiler built-in headers (<stddef.h>
etc)
These headers are formally part of the standard library, but so closely coupled to the parser that they are installed with clangd.
They must be found in ../lib/clang/<version>/include
. If you’ve built clangd
from source or installed it from a package, these should be in the right place.
If you’ve moved the binary around, move it back!
Dealing with crashes
If clangd is exiting unexpectedly, this is probably a crashing bug in clangd. Understanding it better will help you work around it, and if you can file an informative bug report we’ll try to fix it for the next release.
The most helpful crash reports have a log including a (symbolic) stack trace, some idea of what the trigger is, and fairly compact example code that exhibits the problem.
Crashes triggered by requests
If clangd crashes when you go to a particular definition, or hover on a particular name, then the bug is probably in the code handling that request. You can sometimes just avoid doing this!
If you can, try to work out the simplest program that will still exhibit the crash. This is a much more useful/fixable bug report.
Crashes when opening a file
If clangd triggers as soon as you open a particular file, it’s likely a crash when parsing or indexing that file (or an included header). Again it’s very useful to know what’s in the file and minimize it as far as possible (especially include).
A crash goes that goes away when disabling clang-tidy (--clang-tidy=0
) is
likely specific to a particular check and pattern of code.
Note that a background-indexing crash can appear to trigger on file open.
Crashes in background indexing
Unfortunately a crash while background-indexing any file can take down the whole
clangd process. When you start clangd again, it will pick up where it left off,
and crash again. You can tell that this is happening if adding the clangd flag
--background-index=0
avoids the crash.
Typically many files are indexed at once and it can be hard to tell which is
crashing. Pass -j=1 --log=verbose
to clangd to only index one file at a time
and log its name. Once the file is identified, it can also be reduced to a
simpler crashing example.
Getting stacktraces from crashes
clangd
is likely writing a “stack trace” to the logs which helps explain
why it crashed. It may look unhelpful, like this:
/home/me/bin/clangd[0x4f626c]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x13520)[0x7fb6b93c3520]
/home/me/bin/clangd[0x12cc8d2]
...
It will be more useful if you have llvm-symbolizer
on your PATH.
0x00000000004f626c llvm::sys::RunSignalHandlers()
0x00007fe04358f520 __restore_rt
0x00000000012cc8d2 clang::Parser::ParseDirectDeclarator()
...
This is typically part of the llvm
package.
It may be installed as e.g. llvm-symbolizer-10
, and you need to add a symlink.