Claude Code: Node.js Hooks Triggered On Python Projects
h1. Claude Code: Node.js Hooks Triggered on Python Projects
Are you working on a Python project and finding yourself bombarded with confusing npm and biome errors every time you try to make a change? You're not alone! Many developers have encountered a peculiar issue where Claude Code incorrectly executes Node.js hooks on Python projects. This often leads to frustrating "ENOENT" errors, especially after using the Edit tool, even when your project has absolutely no JavaScript or Node.js components. Let's dive deep into why this happens and how it can be fixed.
The Problem: Unexpected Node.js Hooks in Python Projects
If you've encountered the error message:
⏺ PostToolUse:Edit [cd "$CLAUDE_PROJECT_DIR" && npm run biome:check] failed with non-blocking status
code 254: npm error code ENOENT
npm error syscall open
npm error path /Users/devhub/WebstormProjects/polirate/political-fraud-detection-ml/package.json
npm error errno -2
npm error enoent Could not read package.json: Error: ENOENT: no such file or directory, open
'/Users/devhub/WebstormProjects/polirate/polirate/political-fraud-detection-ml/package.json'
then you've hit the nail on the head. This error clearly indicates that Claude Code is attempting to run npm run biome:check and is failing because it can't find a package.json file. The core of the issue is that Claude Code is executing npm/biome PostToolUse hooks on Python FastAPI projects that lack a package.json file. This is particularly baffling in environments where the project is a pure Python FastAPI ML service, with no JavaScript dependencies or configuration whatsoever.
Environment Details and Project Configuration
To understand the root cause, it's essential to look at the specific environment and project setup. In the example reported, the environment is macOS (Darwin 24.5.0), using the latest Claude Code version. The project itself is a Python FastAPI ML service located at /Users/devhub/WebstormProjects/polirate/political-fraud-detection-ml. This project uses Python 3.11+, the FastAPI framework, SQLAlchemy with PostgreSQL, and libraries like scikit-learn and TensorFlow for machine learning. Dependency management is handled by Poetry/pip, with files like requirements.txt, pyproject.toml, and alembic.ini present. Crucially, there are no JavaScript or Node.js components in this project.
Despite thorough investigations into potential hook configurations, no explicit npm or biome hooks were found in the project's .claude directory. Files like .claude/config/hooks.json, .claude/settings.json, and .claude/settings.local.json were checked. The hooks.json file, for instance, only contained Python-specific hooks using the code-style-guardian agent, with no references to npm or biome. Searching the entire .claude directory for "npm", "biome", or "PostToolUse" yielded no matches. This strongly suggests that the problematic hooks are not defined by the user but are being applied by default or through some form of inheritance.
Root Cause Analysis: Cross-Project Hook Inheritance
The most plausible explanation for this behavior is cross-project hook inheritance. Claude Code appears to be applying a default or hardcoded npm/biome PostToolUse hook universally, regardless of the project's actual language or configuration. In a multi-project workspace, it's possible that hooks defined for a sibling Node.js project are being inadvertently applied to the Python project. This bypasses the project-specific hook configurations that only define Python tooling and ignores the absence of JavaScript-related files like package.json.
Why is this Happening?
Claude Code's intention is to automate development workflows by executing relevant hooks. However, in this scenario, the tool is failing to accurately detect the project's context. It seems to operate under the assumption that if any project in the workspace uses Node.js tooling, then all projects might benefit from or require these hooks, which is clearly not the case. This leads to an incorrect execution path where language-agnostic or environment-wide default hooks are triggered even when they are entirely irrelevant and, in this case, detrimental to the development process.
The core problem lies in the lack of proper project type detection before executing language-specific hooks. A robust system should first identify whether a project is Python, JavaScript, Go, etc., based on the presence of defining files (like requirements.txt, pyproject.toml for Python, or package.json for Node.js) and file extensions. Only after correct identification should it proceed to run relevant tooling hooks. Without this crucial step, tools can make incorrect assumptions and cause the kind of errors seen here.
Furthermore, the issue highlights a potential misunderstanding of how hooks should be applied in a multi-project setup. Instead of inheriting or applying default hooks broadly, Claude Code should strictly adhere to project-specific configurations and context. If a .claude/config/hooks.json file exists and defines specific hooks, those should take precedence. If no JavaScript hooks are explicitly defined for a Python project, then no JavaScript hooks should be executed. The current behavior suggests that some default Node.js hooks are being injected or enforced, overriding or ignoring the project's actual configuration and nature.
This problem is exacerbated by the fact that there's no package.json file in the Python project. This file is the standard indicator for Node.js projects, and its absence should be a clear signal to not run any npm or biome commands. The fact that the tool attempts to run them anyway points to a flaw in its execution logic or a misconfiguration in how it manages tool execution across different project types within a single workspace.
Expected vs. Actual Behavior
Expected Behavior:
- Accurate Project Type Detection: Claude Code should correctly identify that the project is a Python FastAPI service based on its file structure and configuration files (
requirements.txt,pyproject.toml, etc.). - Conditional Hook Execution: It should not execute JavaScript/Node.js hooks (like npm or biome) on a Python project.
- Respect for Project Configuration: It should strictly follow the project-specific hook configurations defined in
.claude/config/hooks.jsonand avoid injecting default hooks that conflict with the project's language.
Actual Behavior:
- Claude Code executes npm/biome hooks despite the project being pure Python.
- It attempts to run commands that rely on a
package.jsonfile, which does not exist. - This leads to consistent "ENOENT" errors every time the Edit tool is used, creating unnecessary noise and confusion.
Reproduction Steps
To reproduce this issue, follow these simple steps:
- Set up a Python project: Create a new Python project or use an existing one. Ensure it does not have a
package.jsonfile. A simple Python FastAPI project, as described earlier, would work perfectly. - Configure Claude Code hooks (optional but recommended): Within your project's
.claude/config/directory, create or modifyhooks.json. Add only Python-specific hooks. For example, you might configure a hook for a Python linter or formatter. - Use the Edit tool: Interact with Claude Code, specifically using the Edit tool to modify a file within your Python project.
- Observe the error: After using the Edit tool, check the output. You should see the npm/biome
ENOENTerror, indicating that Node.js hooks are being executed inappropriately.
This straightforward reproduction process highlights the severity and frequency of the problem. The impact, while currently classified as minor because it's non-blocking, significantly degrades the user experience by introducing constant visual clutter and potential confusion about the project's setup and Claude Code's configuration.
Suggested Fixes for Claude Code
To resolve this persistent issue and improve the overall user experience, several key improvements should be implemented in Claude Code:
-
Enhance Project Type Detection: Claude Code needs a more sophisticated mechanism to detect the primary language and tooling of a project. This should involve checking for the presence and relevance of project definition files such as
package.json(for Node.js/JavaScript),requirements.txtorpyproject.toml(for Python),pom.xml(for Java),go.mod(for Go), etc. The tool should prioritize these indicators to accurately categorize the project before attempting to run any language-specific hooks. -
Conditional Execution of Language-Specific Hooks: Based on the detected project type, Claude Code should conditionally execute hooks. For instance, npm/biome hooks should only be triggered if the project is identified as a JavaScript or TypeScript project, typically by the presence of a
package.jsonfile and associated Node.js dependencies. Similarly, Python hooks should only run on Python projects, Java hooks on Java projects, and so on. This prevents the erroneous execution of irrelevant tooling. -
Respect User-Defined Hook Configurations: The tool must strictly adhere to the user's defined hook configurations, such as those found in
.claude/config/hooks.json. If a user has explicitly configured only Python-specific hooks, Claude Code should not inject or default to running Node.js hooks. User configurations should always take precedence over any assumed defaults, especially when those defaults are contextually incorrect. -
Prevent Cross-Language Hook Contamination: Implement logic to ensure that hooks from one project type do not