RustPython/RustPython · error · ArgumentTypeError

can't open '%(filename)s': %(error)s

Error message

can't open '%(filename)s': %(error)s

What it means

When the open() call inside FileType.__call__ raises OSError (missing file, missing directory, permission denied), the error is caught and re-raised as ArgumentTypeError carrying the path and the underlying message. parse_args turns this into a usage message on stderr and SystemExit with status 2, so the program stops before your code runs.

Source

Thrown at Lib/argparse.py:1385

    def __call__(self, string):
        # the special argument "-" means sys.std{in,out}
        if string == '-':
            if 'r' in self._mode:
                return _sys.stdin.buffer if 'b' in self._mode else _sys.stdin
            elif any(c in self._mode for c in 'wax'):
                return _sys.stdout.buffer if 'b' in self._mode else _sys.stdout
            else:
                msg = _('argument "-" with mode %r') % self._mode
                raise ValueError(msg)

        # all other arguments are used as file names
        try:
            return open(string, self._mode, self._bufsize, self._encoding,
                        self._errors)
        except OSError as e:
            args = {'filename': string, 'error': e}
            message = _("can't open '%(filename)s': %(error)s")
            raise ArgumentTypeError(message % args)

    def __repr__(self):
        args = self._mode, self._bufsize
        kwargs = [('encoding', self._encoding), ('errors', self._errors)]
        args_str = ', '.join([repr(arg) for arg in args if arg != -1] +
                             ['%s=%r' % (kw, arg) for kw, arg in kwargs
                              if arg is not None])
        return '%s(%s)' % (type(self).__name__, args_str)

# ===========================
# Optional and Positional Parsing
# ===========================

class Namespace(_AttributeHolder):
    """Simple object for storing attributes.

    Implements equality by attribute names and values, and provides a simple
    string representation.

View on GitHub (pinned to aaeab4f754)

Solutions

  1. Pass a correct, existing (read modes) or writable (write modes) path; create parent directories first.
  2. Use type=str plus your own open() later, wrapped in try/except, so the error is reportable.
  3. Pre-validate known paths before parse_args and fail with your own message.

Example fix

# before
parser.add_argument('--out', type=argparse.FileType('w'))
# after
parser.add_argument('--out', type=str)
args = parser.parse_args()
with open(args.out, 'w') as out:
    out.write(data)
Defensive patterns

Strategy: try-catch

Validate before calling

def readable_file(path):
    import os
    if not os.path.isfile(path):
        raise argparse.ArgumentTypeError('file not found: ' + path)
    return path
# use: parser.add_argument('-i', type=readable_file)

Try / catch

# keep paths as strings at parse time; open later with explicit handling
try:
    stream = open(args.out, 'w')
except OSError as exc:
    sys.exit('cannot open output file: ' + str(exc))

Prevention

When it happens

Trigger: add_argument('-i', type=argparse.FileType('r')) with a nonexistent path; FileType('w') where the parent directory does not exist or is not writable.

Common situations: Relative paths resolved from a different working directory (cron, systemd, containers); permission-denied on protected paths; paths coming from environment variables or upstream services.

Related errors


AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17). Data as JSON: /api/errors/f3e0074459a6b5d7. Report an issue: GitHub.