[REQ] Fix unnecessary printing "no stderr output" after running hook successfully

Resolved 💬 4 comments Opened Jul 6, 2025 by lior-airis Closed Jul 8, 2025

Environment

  • Platform (select one):
  • [ ] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [ ] Other: <!-- specify -->
  • Claude CLI version: <!-- output of claude --version --> 1.0.43
  • Operating System: <!-- e.g. macOS 14.3, Windows 11, Ubuntu 22.04 --> Ubuntu 22.04
  • Terminal: <!-- e.g. iTerm2, Terminal App --> SSH terminal

Bug Description

<!-- A clear and concise description of the bug --> Claude code spams on correct tool use:

> MultiEdit operation feedback:
  - [/home/ubuntu/lint_hook.py]: No stderr output

Steps to Reproduce

  1. <!-- First step --> Register my hook script for edit tools (ruff formatting and linting) and try for yourself:
#!/usr/bin/env python3
"""
PostToolUse hook for linting Python files after editing.
This hook runs after Edit, Write, or MultiEdit operations and applies ruff formatting.
"""

import json
import subprocess
import sys


def main():
    """Main function to run linting hook."""
    try:
        # Read hook input data
        hook_data = json.load(sys.stdin)
        tool_input = hook_data.get("tool_input", {})

        # Get the file path from tool input
        file_path = tool_input.get("file_path", "")

        # Only process Python files and only for file editing tools
        if not file_path or not file_path.endswith(".py"):
            # Not a Python file, exit successfully
            print("Ruff: Not a python file, skipping.")
            sys.exit(0)

        # Detect Python version
        python_version = f"py{sys.version_info.major}{sys.version_info.minor}"

        # Run ruff check with import sorting and comprehensive linting
        check_result = subprocess.run(
            [
                "ruff",
                "check",
                "--fix",
                "--select",
                "F,E,W,I",
                "--line-length",
                "120",
                "--target-version",
                python_version,
                file_path,
            ],
            capture_output=True,
            text=True,
        )

        # Run ruff format
        format_result = subprocess.run(
            ["ruff", "format", "--line-length", "120", "--target-version", python_version, file_path],
            capture_output=True,
            text=True,
        )

        # Always print stdout and stderr if they exist
        if check_result.stdout:
            print(check_result.stdout, end="")
        if check_result.stderr:
            print(check_result.stderr, file=sys.stderr, end="")
        if format_result.stdout:
            print(format_result.stdout, end="")
        if format_result.stderr:
            print(format_result.stderr, file=sys.stderr, end="")

        # Check both return codes - both operations must succeed
        if check_result.returncode == 0 and format_result.returncode == 0:
            sys.exit(0)
        else:
            # Exit with code 2 to block and show error to Claude
            sys.exit(2)

    except Exception as e:
        print(f"Hook error: {e}", file=sys.stderr)
        sys.exit(0)  # Don't block on hook errors


if __name__ == "__main__":
    main()

Expected Behavior

<!-- What you expected to happen -->No print if no stderr

Actual Behavior

<!-- What actually happened -->
Prints after tool use:

> MultiEdit operation feedback:
  - [/home/ubuntu/lint_hook.py]: No stderr output

Additional Context

<!-- Add any other context about the problem here, such as screenshots, logs, etc. -->

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗