google/python-fire · error · ValueError

_FindExecutableOnPath(..., pathext='{0}') failed because pat

Error message

_FindExecutableOnPath(..., pathext='{0}') failed because pathext must be an iterable of strings, but got a string.

What it means

In fire/console/files.py, _FindExecutableOnPath validates that its pathext argument is an iterable of strings (like os.pathext defaults ['.COM','.EXE',...]). If a single string is passed, Python would silently iterate it character-by-character, so the library raises ValueError to surface the likely bug (a string instead of a list).

Source

Thrown at fire/console/files.py:50

def _FindExecutableOnPath(executable, path, pathext):
  """Internal function to a find an executable.

  Args:
    executable: The name of the executable to find.
    path: A list of directories to search separated by 'os.pathsep'.
    pathext: An iterable of file name extensions to use.

  Returns:
    str, the path to a file on `path` with name `executable` + `p` for
      `p` in `pathext`.

  Raises:
    ValueError: invalid input.
  """

  if isinstance(pathext, str):
    raise ValueError('_FindExecutableOnPath(..., pathext=\'{0}\') failed '
                     'because pathext must be an iterable of strings, but got '
                     'a string.'.format(pathext))

  # Prioritize preferred extension over earlier in path.
  for ext in pathext:
    for directory in path.split(os.pathsep):
      # Windows can have paths quoted.
      directory = directory.strip('"')
      full = os.path.normpath(os.path.join(directory, executable) + ext)
      # On Windows os.access(full, os.X_OK) is always True.
      if os.path.isfile(full) and os.access(full, os.X_OK):
        return full
  return None


def _PlatformExecutableExtensions(platform):
  if platform == platforms.OperatingSystem.WINDOWS:
    return ('.exe', '.cmd', '.bat', '.com', '.ps1')

View on GitHub (pinned to 716bbc23d7)

Solutions

  1. Wrap the extension(s) in a list: pathext=['.EXE'].
  2. Split the PATHEXT env var: pathext=os.environ.get('PATHEXT', '').split(os.pathsep).
  3. Call the public wrapper FindExecutableOnPath, which supplies sane pathext defaults.

Example fix

// before
_FindExecutableOnPath('git', path, pathext='.EXE')
// after
_FindExecutableOnPath('git', path, pathext=['.EXE'])
Defensive patterns

Strategy: type-guard

Validate before calling

if isinstance(pathext, str):
    pathext = pathext.split(os.pathsep)  # or raise before calling

Type guard

def is_string_iterable(pathext) -> bool:
    return not isinstance(pathext, str) and all(isinstance(x, str) for x in pathext)

Try / catch

try:
    exe = files._FindExecutableOnPath(name, path, pathext)
except ValueError as e:
    print(f'pathext must be a list of strings: {e}'); sys.exit(2)

Prevention

When it happens

Trigger: Calling _FindExecutableOnPath(name, path=..., pathext='.EXE') — passing pathext as a bare string rather than a list/tuple such as ['.EXE']. This typically happens on Windows-style executable resolution.

Common situations: Hard-coding a single PATHEXT entry without wrapping it in a list; reading PATHEXT and passing the whole joined string instead of os.environ['PATHEXT'].split(os.pathsep).

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of google/python-fire@716bbc23d7 (2026-08-28). Data as JSON: /api/errors/ab9f5ad21e06123f. Report an issue: GitHub.