#2282·powerline

file_vcs_status TypeError with pygit2 on Python 3.14: bad argument type for built-in operation

Author: oandoniuCreated Apr 21, 2026Updated Apr 21, 2026

Description

When opening a file from a git repository while the current working directory is outside the repo, the file_vcs_status segment throws a TypeError.

Environment

  • OS: Arch Linux
  • Python: 3.14
  • Powerline: 2.8.4 (Arch package)
  • pygit2: 1.19.2
  • Vim: 9.x with Python3 support

Error

vim /home/user/work/myrepo/./src/file.cpp

2026-04-21 09:03:37,605:ERROR:vim:file_vcs_status:Exception while computing segment: bad argument type for built-in operation
Traceback (most recent call last):
  File "/usr/lib/python3.14/site-packages/powerline/segment.py", line 173, in process_segment
    contents = segment['contents_func'](pl, segment_info)
  File "/usr/lib/python3.14/site-packages/powerline/segment.py", line 412, in <lambda>
    contents_func = lambda pl, segment_info: _contents_func(pl=pl, segment_info=segment_info, **args)
  File "/usr/lib/python3.14/site-packages/powerline/segments/vim/__init__.py", line 570, in file_vcs_status
    status = repo.status(os.path.relpath(name, repo.directory))
  File "/usr/lib/python3.14/site-packages/powerline/lib/vcs/git.py", line 75, in status
    return get_file_status(...)
  File "/usr/lib/python3.14/site-packages/powerline/lib/vcs/__init__.py", line 131, in get_file_status
    file_status_cache[keypath] = ans = get_func(directory, file_path)
  File "/usr/lib/python3.14/site-packages/powerline/lib/vcs/git.py", line 115, in do_status
    status = git.Repository(directory).status_file(path)
TypeError: bad argument type for built-in operation

Root Cause

In Python 3, buffer_name() in powerline/bindings/vim/__init__.py returns bytes (encoded buffer name):

python
def buffer_name(segment_info):
    try:
        name = segment_info['buffer'].name
    except UnicodeDecodeError:
        return vim_bufname(segment_info['bufnr'])
    else:
        return name.encode(segment_info['encoding']) if name else None

This bytes value is then passed to os.path.relpath() which returns bytes, and eventually reaches pygit2.Repository.status_file() which doesn't accept bytes - only strings.

Proposed Fix

In powerline/segments/vim/__init__.py, decode the buffer name before passing to os.path.relpath():

python
@requires_filesystem_watcher
@requires_segment_info
def file_vcs_status(pl, segment_info, create_watcher):
    name = buffer_name(segment_info)
    skip = not (name and (not vim_getbufoption(segment_info, 'buftype')))
    if not skip:
        repo = guess(path=name, create_watcher=create_watcher)
        if repo is not None:
            # Decode bytes to string for os.path.relpath and pygit2 compatibility
            name_str = name.decode() if isinstance(name, bytes) else name
            status = repo.status(os.path.relpath(name_str, repo.directory))
            # ... rest of function

Related Issues

  • #2106 - Similar issue but on Windows with different error ("a bytes-like object is required, not 'str'")
  • #1876 - Similar bytes/str mismatch issue from 2018
  • #2222 - PR for related bytes decoding issue in generate_directories()

The underlying issue is that buffer_name() returns bytes in Python 3, but many downstream functions expect strings.