mlflow/mlflow · error · Exception
Not an S3 URI: {uri}
Error message
Not an S3 URI: {uri} What it means
parse_s3_compliant_uri on OptimizedS3ArtifactRepository only accepts URIs whose scheme is exactly 's3'; anything else raises a plain Exception. It is invoked from the constructor, so a bad URI fails at repo creation time.
Source
Thrown at mlflow/store/artifact/optimized_s3_artifact_repo.py:156
"(e.g., os.environ['AWS_DEFAULT_REGION'] = 'us-gov-west-1')",
error_code=INVALID_PARAMETER_VALUE,
) from error
def _get_s3_client(self):
return _get_s3_client(
addressing_style=self._addressing_style,
access_key_id=self._access_key_id,
secret_access_key=self._secret_access_key,
session_token=self._session_token,
region_name=self._region_name,
s3_endpoint_url=self._s3_endpoint_url,
)
def parse_s3_compliant_uri(self, uri):
"""Parse an S3 URI, returning (bucket, path)"""
parsed = urllib.parse.urlparse(uri)
if parsed.scheme != "s3":
raise Exception(f"Not an S3 URI: {uri}")
path = parsed.path
path = path.removeprefix("/")
return parsed.netloc, path
@staticmethod
def get_s3_file_upload_extra_args():
if s3_file_upload_extra_args := MLFLOW_S3_UPLOAD_EXTRA_ARGS.get():
return json.loads(s3_file_upload_extra_args)
else:
return None
def _upload_file(self, s3_client, local_file, bucket, key):
extra_args = {}
extra_args.update(self._s3_upload_extra_args)
guessed_type, guessed_encoding = guess_type(local_file)
if guessed_type is not None:
extra_args["ContentType"] = guessed_type
if guessed_encoding is not None:View on GitHub (pinned to 6a27f2decc)
Solutions
- Convert the URI to s3:// form: replace the scheme, keeping bucket and key (s3a://bucket/path -> s3://bucket/path).
- Ensure you are constructing the correct repo class for the scheme (e.g., LocalArtifactRepository for file:, R2ArtifactRepository for r2:).
- Validate the URI scheme before constructing the repo.
- Fix string-building bugs that drop or mangle the scheme.
Example fix
// before
repo = OptimizedS3ArtifactRepository("s3a://my-bucket/model")
# after
uri = "s3a://my-bucket/model".replace("s3a://", "s3://", 1)
repo = OptimizedS3ArtifactRepository(uri) Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def ensure_s3_uri(uri: str) -> str:
if urlparse(uri).scheme != "s3":
raise ValueError(f"Expected s3:// URI, got: {uri}")
return uri
ensure_s3_uri(uri) # call before constructing the repo Type guard
def is_s3_uri(uri: str) -> bool:
from urllib.parse import urlparse
return urlparse(uri).scheme == "s3" Try / catch
try:
repo = OptimizedS3ArtifactRepository(uri)
except Exception as e:
if str(e).startswith("Not an S3 URI"):
repo = get_artifact_repository(uri) # route by scheme
else:
raise Prevention
- Normalize s3a:///other schemes to s3:// before artifact-repo calls
- Use mlflow.artifacts utilities rather than instantiating repo classes directly with raw URIs
- Unit-test URI builders to assert scheme == 's3'
When it happens
Trigger: Passing a URI like 's3a://bucket/key', 'file:///path', or an https URL into OptimizedS3ArtifactRepository (directly or via code that assumes S3).
Common situations: Using s3a:// (Spark-style) or S3 endpoints with custom schemes; string concatenation bugs producing malformed URIs; routing non-S3 artifact URIs into the optimized S3 repo.
Related errors
- Not an R2 URI: {uri}
- Invalid trackingUri: '${trackingUri}'. Must be a valid HTTP
- Not a proper deployment URI: {target_uri}. Deployment URIs m
- INVALID_PARAMETER_VALUE
- Invalid endpoint URI: {endpoint_uri}. The endpoint URI must
AI-assisted analysis of mlflow/mlflow@6a27f2decc (2026-08-29).
Data as JSON: /api/errors/396b264cdee4478c.
Report an issue: GitHub.