opendatalab/MinerU · error · ValueError

The provided path starts with '/'. This does not conform to

Error message

The provided path starts with '/'. This does not conform to a valid S3 path format.

What it means

ValueError from parse_s3path() when the (query-stripped, trimmed) path begins with '/'. The function only accepts 's3://bucket/key' or 's3a://bucket/key'; a leading slash means there is no scheme and no bucket segment, so the path cannot be decomposed into (bucket, key).

Source

Thrown at mineru/data/utils/path_utils.py:21

def remove_non_official_s3_args(s3path):
    """
    example: s3://abc/xxxx.json?bytes=0,81350 ==> s3://abc/xxxx.json
    """
    arr = s3path.split("?")
    return arr[0]

def parse_s3path(s3path: str):
    # from s3pathlib import S3Path
    # p = S3Path(remove_non_official_s3_args(s3path))
    # return p.bucket, p.key
    s3path = remove_non_official_s3_args(s3path).strip()
    if s3path.startswith(('s3://', 's3a://')):
        prefix, path = s3path.split('://', 1)
        bucket_name, key = path.split('/', 1)
        return bucket_name, key
    elif s3path.startswith('/'):
        raise ValueError("The provided path starts with '/'. This does not conform to a valid S3 path format.")
    else:
        raise ValueError("Invalid S3 path format. Expected 's3://bucket-name/key' or 's3a://bucket-name/key'.")


def parse_s3_range_params(s3path: str):
    """
    example: s3://abc/xxxx.json?bytes=0,81350 ==> [0, 81350]
    """
    arr = s3path.split("?bytes=")
    if len(arr) == 1:
        return None
    return arr[1].split(",")

View on GitHub (pinned to 4fe4bde114)

Solutions

  1. Pass a proper S3 URI: 's3://bucket/key' (or 's3a://bucket/key').
  2. If you have bucket and key separately, build the URI: f's3://{bucket}/{key}'.
  3. If the path is a local file, use a local reader/writer instead of the S3 one.
  4. Strip a leading '/'mount prefix before composing the s3:// URI.

Example fix

# before
bucket, key = parse_s3path('/my-bucket/doc.pdf')  # ValueError

# after
bucket, key = parse_s3path('s3://my-bucket/doc.pdf')
Defensive patterns

Strategy: validation

Validate before calling

def to_s3_uri(path: str) -> str:
    p = path.strip()
    if p.startswith(('s3://', 's3a://')):
        return p
    if p.startswith('/'):
        return 's3:/' + p  # '/bucket/key' -> 's3://bucket/key'
    raise ValueError(f'cannot convert {path!r} to an s3:// URI')

bucket, key = parse_s3path(to_s3_uri(raw_path))

Type guard

def looks_like_s3_path(path: str) -> bool:
    p = path.strip()
    return p.startswith('s3://') or p.startswith('s3a://')

Try / catch

try:
    bucket, key = parse_s3path(path)
except ValueError as e:
    raise ValueError(f'expected s3://bucket/key, got {path!r}') from e

Prevention

When it happens

Trigger: parse_s3path('/bucket/key.pdf') or parse_s3path('/data/file.pdf'). Called indirectly by MultiBucketS3DataReader.read_at()/write paths when an absolute filesystem-style path is passed instead of an s3:// URI.

Common situations: Mixing local path handling with S3 paths — e.g. os.path.join output, mount paths like '/mnt/s3/bucket', or Path('/bucket/key').as_uri()-style leftovers; refactoring a local-pipeline to S3 without converting path constants.

Related errors


AI-assisted analysis of opendatalab/MinerU@4fe4bde114 (2026-08-14). Data as JSON: /api/errors/71893a68e71b1dbc. Report an issue: GitHub.