{"record":{"id":"5bfb73f9778a17d5","repo":"commaai/openpilot","slug":"unexpected-non-vendored-library-name","errorCode":null,"errorMessage":"Unexpected non-vendored library '{name}'","messagePattern":"Unexpected non-vendored library '(.+?)'","errorType":"exception","errorClass":"SCons.Errors.UserError","httpStatus":null,"severity":"error","filePath":"SConstruct","lineNumber":103,"sourceCode":"# e.g. apt-installed libusb. all libraries should either\n# be distributed with all Linux distros and macOS, or\n# vendored in commaai/dependencies.\nallowed_system_libs = {\n  \"EGL\", \"GLESv2\", \"GL\",\n  \"Qt5Charts\", \"Qt5Core\", \"Qt5Gui\", \"Qt5Widgets\",\n  \"dl\", \"drm\", \"gbm\", \"m\", \"pthread\",\n}\n\ndef _resolve_lib(env, name):\n  for d in env.Flatten(env.get('LIBPATH', [])):\n    p = Dir(str(d)).abspath\n    for ext in ('.a', '.so', '.dylib'):\n      f = File(os.path.join(p, f'lib{name}{ext}'))\n      if f.exists() or f.has_builder():\n        return name\n  if name in allowed_system_libs:\n    return name\n  raise SCons.Errors.UserError(f\"Unexpected non-vendored library '{name}'\")\n\ndef _libflags(target, source, env, for_signature):\n  libs = []\n  lp = env.subst('$LIBLITERALPREFIX')\n  for lib in env.Flatten(env.get('LIBS', [])):\n    if isinstance(lib, str):\n      if os.sep in lib or lib.startswith('#'):\n        libs.append(File(lib))\n      elif lib.startswith('-') or (lp and lib.startswith(lp)):\n        libs.append(lib)\n      else:\n        libs.append(_resolve_lib(env, lib))\n    else:\n      libs.append(lib)\n  return _stripixes(env['LIBLINKPREFIX'], libs, env['LIBLINKSUFFIX'],\n                    env['LIBPREFIXES'], env['LIBSUFFIXES'], env, env['LIBLITERALPREFIX'])\n\nenv = Environment(","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/SConstruct#L85-L121","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"# before\nenv.Append(LIBS=['avcodec'])  # not vendored, not allowlisted -> UserError\n\n# after\n# vendor it:\nenv.Append(CPPPATH=['#third_party/ffmpeg/include'])\nenv.Append(LIBPATH=['#third_party/ffmpeg/lib'])\nenv.Append(LIBS=['avcodec'])  # resolves to third_party/ffmpeg/lib/libavcodec.a","handlingStrategy":"validation","validationCode":"# SConstruct-side: check every LIBS entry resolves before building\nallowed = {'dl', 'drm', 'gbm', 'm', 'pthread'}\nimport os, glob\nfor lib in env.Flatten(env.get('LIBS', [])):\n    if isinstance(lib, str) and os.sep not in lib and not lib.startswith(('-', '#')):\n        found = any(glob.glob(os.path.join(str(d), f'lib{lib}.a')) for d in env.Flatten(env.get('LIBPATH', [])))\n        assert found or lib in allowed, f'lib{lib} not vendored — add it to third_party or LIBPATH'","typeGuard":null,"tryCatchPattern":"try:\n    SConscript('my_component/SConscript')\nexcept SCons.Errors.UserError as e:\n    if 'non-vendored library' in str(e):\n        print('Vendor the library under third_party/ and add its lib dir to LIBPATH')\n    raise","preventionTips":["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."],"tags":["build","scons","linking","vendoring","openpilot"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}