juicedata/juicefs · error · ValueError

invalid mode: {mode}

Error message

invalid mode: {mode}

What it means

JuiceFileSystem.open() validates the mode string like builtin open(): it rejects modes containing duplicate characters (len(mode) != len(set(mode))) and unknown characters. This specific raise covers both duplicate characters and any character not in 'rwxa+tb' encountered in the parse loop. It's a fail-fast ValueError before any file operation.

Source

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

    def stat(self, path):
        """Get the status of a file or a directory."""
        fi = FileInfo()
        self.lib.jfs_stat(c_int64(_tid()), c_int64(self.h), _bin(path), byref(fi))
        return os.stat_result((fi.mode, fi.inode, 0, fi.nlink, fi.uid, fi.gid, fi.length, fi.atime, fi.mtime, fi.ctime))

    def exists(self, path):
        """Check if a file exists."""
        try:
            self.stat(path)
            return True
        except OSError as e:
            return False

    def open(self, path, mode='r', buffering=-1, encoding=None, errors=None):
        """Open a file, returns a filelike object."""
        if len(mode) != len(set(mode)):
            raise ValueError(f'invalid mode: {mode}')
        flag = 0
        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")

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Use a mode with unique characters drawn only from 'rwxa', plus optional '+' and 'tb'.
  2. Include exactly one of r/w/x/a — see also the cnt != 1 check.
  3. Match Python's builtin open() mode grammar: e.g. 'r', 'rb', 'w', 'w+', 'a'.

Example fix

# before
f = jfs.open(path, 'rw')  # duplicates? 'rw' ok, but 'rr' or 'rww' fails
# after
f = jfs.open(path, 'r+')  # read+write with a single 'r'/'w' base
Defensive patterns

Strategy: validation

Validate before calling

def validate_mode(mode):
    if len(mode) != len(set(mode)) or any(c not in 'rwxa+tb' for c in mode):
        raise ValueError(f'invalid mode: {mode}')
    return mode

Type guard

def is_valid_mode(mode) -> bool:
    return isinstance(mode, str) and len(mode) == len(set(mode)) and all(c in 'rwxa+tb' for c in mode)

Try / catch

try:
    f = jfs.open(path, mode)
except ValueError as e:
    if 'invalid mode' in str(e):
        mode = sanitize_mode(mode)
        f = jfs.open(path, mode)
    else:
        raise

Prevention

When it happens

Trigger: open(path, 'rr'), open(path, 'w+w'), or open(path, 'q') — any mode with a repeated character or a character outside rwxa+tb.

Common situations: Programmatically building a mode string and duplicating flags; typos ('re' containing 'e'); porting code that uses C-style modes like 'rb+' is fine, but 'z' or 'O_RDWR' constants leaked into the string are not.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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