juicedata/juicefs · error · ValueError

binary mode doesn't take an encoding argument

Error message

binary mode doesn't take an encoding argument

What it means

In binary mode, text decoding parameters are meaningless: open() raises ValueError when encoding (and separately errors/newline) is passed together with a mode containing 'b'. This matches CPython's builtin open() behavior for the JuiceFileSystem wrapper.

Source

Thrown at sdk/python/juicefs/juicefs/juicefs.py:225

        cnt = 0
        for c in mode:
            if c in 'rwxa':
                cnt += 1
                if c == 'r':
                    flag |= MODE_READ
                else:
                    flag |= MODE_WRITE
            elif c == '+':
                flag |= MODE_READ | MODE_WRITE
            elif c not in 'tb':
                raise ValueError(f'invalid mode: {mode}')
        if cnt != 1:
            raise ValueError('must have exactly one of create/read/write/append mode')
        if 'b' in mode:
            if 't' in mode:
                raise ValueError("can't have text and binary mode at once")
            if encoding:
                raise ValueError("binary mode doesn't take an encoding argument")
            if errors:
                raise ValueError("binary mode doesn't take an errors argument")
        else:
            if not encoding:
                encoding = locale.getpreferredencoding(False).lower()
            if not errors:
                errors = 'strict'
            codecs.lookup(encoding)

        size = 0
        if 'x' in mode:
            fd = self.lib.jfs_create(c_int64(_tid()), c_int64(self.h), _bin(path), c_uint16(0o666), c_uint16(self.umask))
        else:
            try:
                sz = c_uint64()
                fd = self.lib.jfs_open_posix(c_int64(_tid()), c_int64(self.h), _bin(path), byref(sz), c_int32(flag))
                if 'w' in mode:
                    self.lib.jfs_ftruncate(c_int64(_tid()), fd, c_uint64(0))

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Drop the encoding argument when using a binary mode.
  2. If decoding is needed, switch to text mode ('r'/'w') and keep encoding.
  3. Pass encoding=None conditionally based on whether 'b' is in the mode.

Example fix

# before
f = jfs.open(path, 'rb', encoding='utf-8')
# after
f = jfs.open(path, 'rb')  # or jfs.open(path, 'r', encoding='utf-8')
Defensive patterns

Strategy: validation

Validate before calling

if 'b' in mode and encoding is not None:
    raise ValueError("encoding is not allowed in binary mode")

Type guard

def is_valid_open_call(path, mode, encoding=None) -> bool:
    return not ('b' in mode and encoding is not None)

Try / catch

try:
    f = jfs.open(path, mode, encoding=encoding)
except ValueError as e:
    if "binary mode doesn't take an encoding" in str(e):
        f = jfs.open(path, mode)
    else:
        raise

Prevention

When it happens

Trigger: jfs.open(path, 'rb', encoding='utf-8') or jfs.open(path, 'wb', errors='ignore') — any binary mode combined with a non-None encoding argument.

Common situations: Passing through kwargs from a generic file-opener that always supplies encoding; refactored code that switched mode from 'r' to 'rb' but left encoding in the call; default encoding values injected by wrappers.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/0f6fe85feb20beb5. Report an issue: GitHub.