commaai/openpilot · error · SCons.Errors.UserError
Unexpected non-vendored library '{name}'
Error message
Unexpected non-vendored library '{name}' What it means
Raised by _resolve_lib in the root SConstruct when a library named in LIBS is not found in any configured LIBPATH (as lib<name>.a/.so/.dylib) and is not in the small allowed_system_libs allowlist (dl, drm, gbm, m, pthread). This is openpilot's vendoring guard: every third-party dependency must either be built/vendored into the tree or explicitly allowlisted, so accidental dynamic dependencies on host packages fail the build with a UserError.
Source
Thrown at SConstruct:103
# e.g. apt-installed libusb. all libraries should either
# be distributed with all Linux distros and macOS, or
# vendored in commaai/dependencies.
allowed_system_libs = {
"EGL", "GLESv2", "GL",
"Qt5Charts", "Qt5Core", "Qt5Gui", "Qt5Widgets",
"dl", "drm", "gbm", "m", "pthread",
}
def _resolve_lib(env, name):
for d in env.Flatten(env.get('LIBPATH', [])):
p = Dir(str(d)).abspath
for ext in ('.a', '.so', '.dylib'):
f = File(os.path.join(p, f'lib{name}{ext}'))
if f.exists() or f.has_builder():
return name
if name in allowed_system_libs:
return name
raise SCons.Errors.UserError(f"Unexpected non-vendored library '{name}'")
def _libflags(target, source, env, for_signature):
libs = []
lp = env.subst('$LIBLITERALPREFIX')
for lib in env.Flatten(env.get('LIBS', [])):
if isinstance(lib, str):
if os.sep in lib or lib.startswith('#'):
libs.append(File(lib))
elif lib.startswith('-') or (lp and lib.startswith(lp)):
libs.append(lib)
else:
libs.append(_resolve_lib(env, lib))
else:
libs.append(lib)
return _stripixes(env['LIBLINKPREFIX'], libs, env['LIBLINKSUFFIX'],
env['LIBPREFIXES'], env['LIBSUFFIXES'], env, env['LIBLITERALPREFIX'])
env = Environment(View on GitHub (pinned to 516ec1e682)
Solutions
- Vendor/build the library inside the tree (typically under third_party/) and add its output directory to LIBPATH so lib<name>.a exists before linking.
- If the library genuinely must come from the system, add its name to allowed_system_libs in SConstruct — but upstream review will likely reject this for openpilot targets.
- Check for a typo in the LIBS entry; _resolve_lib only looks for files literally named lib<name>.<ext>.
- If a vendored lib is missing, re-run scons after checking that the third_party fetch/clone step succeeded (clean the relevant target and rebuild).
Example fix
# before env.Append(LIBS=['avcodec']) # not vendored, not allowlisted -> UserError # after # vendor it: env.Append(CPPPATH=['#third_party/ffmpeg/include']) env.Append(LIBPATH=['#third_party/ffmpeg/lib']) env.Append(LIBS=['avcodec']) # resolves to third_party/ffmpeg/lib/libavcodec.a
Defensive patterns
Strategy: validation
Validate before calling
# SConstruct-side: check every LIBS entry resolves before building
allowed = {'dl', 'drm', 'gbm', 'm', 'pthread'}
import os, glob
for lib in env.Flatten(env.get('LIBS', [])):
if isinstance(lib, str) and os.sep not in lib and not lib.startswith(('-', '#')):
found = any(glob.glob(os.path.join(str(d), f'lib{lib}.a')) for d in env.Flatten(env.get('LIBPATH', [])))
assert found or lib in allowed, f'lib{lib} not vendored — add it to third_party or LIBPATH' Try / catch
try:
SConscript('my_component/SConscript')
except SCons.Errors.UserError as e:
if 'non-vendored library' in str(e):
print('Vendor the library under third_party/ and add its lib dir to LIBPATH')
raise Prevention
- Always vendor new dependencies into the tree and add their output dir to LIBPATH.
- Use exact library names matching lib<name>.a files on disk.
- Keep allowed_system_libs changes minimal and deliberate; upstream enforces vendoring.
When it happens
Trigger: Adding a SConscript that does env.Append(LIBS=['avcodec']) (or any non-allowlisted name) without also vendoring/building the library into a directory on LIBPATH. Also triggered by typo'd library names, or by relying on system-installed dev packages that upstream refuses to link dynamically.
Common situations: Contributors porting new codec/IPC deps and assuming apt-installed libraries will be picked up; stale checkouts missing a vendored third_party lib after a fetch failure; CI environments where the prebuilt vendored libs were not downloaded.
Related errors
- {t} is {size / (1024 * 1024):.1f} MiB, exceeding the {limit
- invalid build metadata
- no product string in wrapped firmware
- bundled firmware is {expected_product!r}, expected version {
- cannot recover from the ROM bootloader without a config back
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/5bfb73f9778a17d5.
Report an issue: GitHub.