{"record":{"id":"bbce8e37e969af2c","repo":"oraios/serena","slug":"shellcheck-binary-not-found-at-binary-path-after","errorCode":null,"errorMessage":"ShellCheck binary not found at {binary_path} after extraction; archive layout may have changed.","messagePattern":"ShellCheck binary not found at (.+?) after extraction; archive layout may have changed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/solidlsp/language_servers/bash_language_server.py","lineNumber":181,"sourceCode":"            install_dir = _shellcheck_install_dir(bash_ls_dir)\n            os.makedirs(install_dir, exist_ok=True)\n\n            release = _SHELLCHECK_DEPENDENCIES.get(PlatformUtils.get_platform_id())\n            if release is None:\n                raise RuntimeError(f\"ShellCheck has no upstream binary release for platform {PlatformUtils.get_platform_id().value}\")\n\n            archive_type = \"zip\" if os.name == \"nt\" else \"xztar\"\n            log.info(f\"Downloading ShellCheck v{_SHELLCHECK_VERSION} for {PlatformUtils.get_platform_id().value}\")\n            FileUtils.download_and_extract_archive_verified(\n                release[\"url\"],\n                install_dir,\n                archive_type,\n                expected_sha256=release[\"sha256\"],\n                allowed_hosts=_SHELLCHECK_ALLOWED_HOSTS,\n            )\n\n            if not os.path.exists(binary_path):\n                raise FileNotFoundError(f\"ShellCheck binary not found at {binary_path} after extraction; archive layout may have changed.\")\n\n            # ensure the binary is executable on POSIX (zip extraction does not preserve perms)\n            if os.name != \"nt\":\n                current = os.stat(binary_path).st_mode\n                os.chmod(binary_path, current | 0o111)\n\n        def create_launch_command_env(self) -> dict[str, str]:\n            bash_language_server_version = self._custom_settings.get(\"bash_language_server_version\", DEFAULT_BASH_LANGUAGE_SERVER_VERSION)\n            bash_ls_dir = self._resolve_bash_ls_dir(bash_language_server_version)\n            managed_bin_dir = os.path.join(bash_ls_dir, \"node_modules\", \".bin\")\n            return {\n                \"PATH\": managed_bin_dir + os.pathsep + os.environ.get(\"PATH\", \"\"),\n                \"SHELLCHECK_PATH\": _shellcheck_binary_path(bash_ls_dir),\n            }\n\n        def _resolve_bash_ls_dir(self, bash_language_server_version: str) -> str:\n            # legacy unversioned dir reserved for INITIAL; every other version goes into a versioned subdir\n            ls_dirname = (","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/oraios/serena/blob/7fcbca7e62555ec2287ddb2f083caee805848ea6/src/solidlsp/language_servers/bash_language_server.py#L163-L199","documentation":"Raised by _install_shellcheck_if_missing after downloading and extracting the ShellCheck release archive: the expected shellcheck binary was not found at its expected path. The library throws this because it downloads a pinned release and assumes a known archive layout; if the binary is missing after extraction, the upstream archive structure likely changed or the extraction silently failed.","triggerScenarios":"Calling BashLanguageServer startup (_get_or_install_core_dependency -> _install_shellcheck_if_missing) when shellcheck is not already present, the pinned release URL/SHA is downloaded and extracted successfully, but _shellcheck_binary_path(bash_ls_dir) does not exist afterwards (e.g. archive now nests the binary in a different subdirectory, partial extraction, or disk issue).","commonSituations":"Upstream ShellCheck GitHub release changes its archive layout (renames/renests the binary); corrupted or truncated download that extracts but omits the binary; a proxy/mirror serving a different archive; filesystem errors during extraction; a stale pinned version in the library.","solutions":["Check the extracted directory (ls the install dir under bash-lsp*/shellcheck) to see the actual archive layout and where the binary landed","Clear the managed install directory so a fresh download/extraction is attempted","Pin/report the ShellCheck version: install shellcheck system-wide via package manager so the managed install is skipped (os.path.exists early-returns)","Update the library to a version matching the current upstream ShellCheck archive layout"],"exampleFix":"# before (managed install fails)\nBashLanguageServer(...)  # raises FileNotFoundError after extraction\n// after\n# pre-install shellcheck system-wide so the managed install path is skipped\nsudo apt-get install shellcheck\nBashLanguageServer(...)  # works","handlingStrategy":"validation","validationCode":"import os, shutil\nif shutil.which(\"shellcheck\") is None and not os.path.exists(os.path.join(ls_resources_dir, \"bash-lsp\", \"shellcheck\", \"shellcheck\")):\n    print(\"shellcheck will be managed-installed; if it fails, pre-install shellcheck system-wide\")","typeGuard":null,"tryCatchPattern":"try:\n    BashLanguageServer(...)\nexcept FileNotFoundError as e:\n    if \"ShellCheck binary not found\" in str(e):\n        # fall back to system shellcheck or clear the install dir and retry\n        shutil.which(\"shellcheck\") or install_shellcheck_via_pkg_manager()\n    else:\n        raise","preventionTips":["Pre-install shellcheck via your system package manager so the managed download path is never used","Clear the managed bash-lsp install directory after upgrading the library or shellcheck version","Check the extracted archive layout if you pin a custom bash_language_server_version"],"tags":["shellcheck","installation","archive-layout","bash"],"backgroundTag":"language-server-binary-install-failed","analyzedSha":"7fcbca7e62555ec2287ddb2f083caee805848ea6","analyzedAt":"2026-08-29T00:04:09.619Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}