Skip to content

Problem executing cz commit in prepare-commit-msg hook on Mac聽#1386

Description

@suityou01

Description

I have a hook that attempts to redirect to commitzen like so

exec < /dev/tty && cz commit || true

This works on linux. Unfortunately at work we are on Mac 馃憥

This is the error I get

File "/opt/homebrew/bin/cz", line 8, in <module> sys.exit(main()) ~~~~^^ File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/commitizen/cli.py", line 656, in main args.func(conf, arguments)() ~~~~~~~~~~~~~~~~~~~~~~~~~~^^ File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/commitizen/commands/commit.py", line 127, in __call__ m = self.prompt_commit_questions() File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/commitizen/commands/commit.py", line 58, in prompt_commit_questions answers = questionary.prompt(questions, style=cz.style) File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/questionary/prompt.py", line 78, in prompt return unsafe_prompt(questions, answers, patch_stdout, true_color, **kwargs) File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/questionary/prompt.py", line 221, in unsafe_prompt answer = question.unsafe_ask(patch_stdout) File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/questionary/question.py", line 89, in unsafe_ask return self.application.run() ~~~~~~~~~~~~~~~~~~~~^^ File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/prompt_toolkit/application/application.py", line 1002, in run return asyncio.run(coro) ~~~~~~~~~~~^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 195, in run return runner.run(main) ~~~~~~~~~~^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/base_events.py", line 725, in run_until_complete return future.result() ~~~~~~~~~~~~~^^ File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/prompt_toolkit/application/application.py", line 886, in run_async return await _run_async(f) ^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/prompt_toolkit/application/application.py", line 734, in _run_async with self.input.raw_mode(), self.input.attach( ~~~~~~~~~~~~~~~~~^ read_from_input_in_context ^^^^^^^^^^^^^^^^^^^^^^^^^^ ), attach_winch_signal_handler(self._on_resize): ^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/contextlib.py", line 141, in __enter__ return next(self.gen) File "/opt/homebrew/Cellar/commitizen/4.5.1/libexec/lib/python3.13/site-packages/prompt_toolkit/input/vt100.py", line 165, in _attached_input loop.add_reader(fd, callback_wrapper) ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/selector_events.py", line 347, in add_reader self._add_reader(fd, callback, *args) ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/asyncio/selector_events.py", line 279, in _add_reader self._selector.register(fd, selectors.EVENT_READ, ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ (handle, None)) ^^^^^^^^^^^^^^^ File "/opt/homebrew/Cellar/python@3.13/3.13.2/Frameworks/Python.framework/Versions/3.13/lib/python3.13/selectors.py", line 505, in register self._selector.control([kev], 0, 0) ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^ OSError: [Errno 22] Invalid argument

I am not sure what the Invalid argument is given that no arguments are being passed to the command.

Steps to reproduce

  1. Buy a Mac
  2. Create a github prepare-commit-msg hook in your project
  3. Git commit

Current behavior

Stack trace

Desired behavior

Works

Screenshots

No response

Environment

  • commitizen version : 4.5.1

Activity

  1. bearomorphism commented on May 9, 2026

    @bearomorphism
    Collaborator

    Re-examining this in context of the round-2 triage (#1965): the root cause is the prepare-commit-msg hook running inside git commit's standard-input redirection, which leaves prompt_toolkit (via questionary.prompt) without a real TTY. The exec < /dev/tty && cz commit || true workaround works on Linux because /dev/tty reattaches stdin to the controlling terminal; on macOS the asyncio selector implementation (KqueueSelector) refuses the resulting fd with OSError: [Errno 22] Invalid argument.

    A clean fix would need to either:

    1. detect "no usable TTY" before invoking questionary.prompt and emit a clear error pointing at cz commit --edit / git commit --edit instead, or
    2. re-route the stdin / stdout dance so prompt_toolkit doesn't choke on the kqueue mismatch (probably involving prompt_toolkit.input.create_input(stdin=open('/dev/tty')) on Darwin).

    Option 1 is small and unblocks #1393 (the request to ship a prepare-commit-msg hook entry); option 2 actually makes the hook work on Mac. Either should be a separate, focused PR. Flagging here that this is the gating bug for #1393 and that the macOS asyncio path is the actual technical wall.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions