Skip to content

[Bug] ivy-done: REQUIRE-MATCH function called with 0 arguments instead of 1, violating completing-read contract #3082

@ianyepan

Description

@ianyepan

This is a corrected and enhanced report of #3081.

In ivy-done, when REQUIRE-MATCH is a function, Ivy calls it with zero arguments. However, the Emacs completing-read specification states that a function passed as REQUIRE-MATCH should be called with the input as the argument.

From the completing-read docstring:

REQUIRE-MATCH can take the following values:
...

  • a function, which will be called with the input as the argument. If the function returns a non-nil value, the minibuffer is exited with that argument as the value.

This causes a wrong-number-of-arguments error when packages (e.g., Magit) correctly pass a 1-arity function as REQUIRE-MATCH.

Steps to Reproduce

  1. Enable ivy-mode
  2. Invoke a command that passes a function as REQUIRE-MATCH to completing-read. For example, in Magit: magit-statusb c (branch and checkout)
  3. Type a branch name and press RET

Backtrace

(wrong-number-of-arguments (1 . 1) 0)
  #f(compiled-function (choice) #<bytecode 0x1bef4b8e62911372>)()
  ivy-done()
  ivy-alt-done(nil)
  funcall-interactively(ivy-alt-done nil)
  call-interactively(ivy-alt-done nil nil)
  command-execute(ivy-alt-done)
  read-from-minibuffer("Name for new branch: " ...)
  ivy-read("Name for new branch: " ... :require-match #f(compiled-function (choice) ...) ...)
  ivy-completing-read("Name for new branch: " ... nil #f(compiled-function (choice) ...) ...)
  completing-read("Name for new branch: " ... nil #f(compiled-function (choice) ...) ...)
  magit-completing-read("Name for new branch" nil nil #f(compiled-function (choice) ...))
  magit-branch--read-name("Name for new branch" "origin/master")
  magit-branch-read-args("Create and checkout branch")

Root Cause

In ivy-done (ivy.el), the relevant cond clause:

((or (and (memq (ivy-state-collection ivy-last)
                '(read-file-name-internal internal-complete-buffer))
          (eq confirm-nonexistent-file-or-buffer t))
     (and (functionp require-match)
          (setq require-match (funcall require-match))))  ;; ← BUG: 0 args

(funcall require-match) is called with no arguments, but per the completing-read contract, it should be called with the current input.

Suggested Fix

;; Before (broken):
(funcall require-match)

;; After (correct per completing-read spec):
(funcall require-match ivy-text) ; or some other valid argument

Environment

  • Emacs: 30.2 (tested both TUI and GUI)
  • Ivy/Swiper/Counsel: latest
  • Triggered by: Magit (latest)
  • OS: Bug experienced and fix tested on macOS, Redhat-based Linux, and WSL2 Ubuntu

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions