{"record":{"id":"8fad59eef877d623","repo":"mlflow/mlflow","slug":"not-a-proper-scheme-uri-uri-entity-type","errorCode":null,"errorMessage":"Not a proper {scheme}:/ URI: {uri}. {entity_type} URIs must be of the form '{scheme}:/name/suffix' or '{scheme}:/name@alias' where suffix is a version, stage, or the string 'latest' and where alias is a registered {scheme[:-1]} alias. Only one of suffix or alias can be defined at a time.","messagePattern":"Not a proper (.+?):/ URI: (.+?)\\. (.+?) URIs must be of the form '(.+?):/name/suffix' or '(.+?):/name@alias' where suffix is a version, stage, or the string 'latest' and where alias is a registered (.+?) alias\\. Only one of suffix or alias can be defined at a time\\.","errorType":"exception","errorClass":"MlflowException","httpStatus":null,"severity":"error","filePath":"mlflow/store/artifact/utils/models.py","lineNumber":75,"sourceCode":"\n\ndef _parse_model_uri(uri, scheme: str = \"models\") -> ParsedModelUri:\n    \"\"\"\n    Returns a ParsedModelUri tuple. Since a models:/ or prompts:/ URI can only have one of\n    {version, stage, 'latest', alias}, it will return\n        - (id, None, None, None) to look for a specific model by ID,\n        - (name, version, None, None) to look for a specific version,\n        - (name, None, stage, None) to look for the latest version of a stage,\n        - (name, None, None, None) to look for the latest of all versions.\n        - (name, None, None, alias) to look for a registered model alias.\n\n    Args:\n        uri: The URI to parse (e.g., \"models:/name/version\" or \"prompts:/name@alias\")\n        scheme: The expected URI scheme (default: \"models\", can be \"prompts\")\n    \"\"\"\n    parsed = urllib.parse.urlparse(uri, allow_fragments=False)\n    if parsed.scheme != scheme:\n        raise MlflowException(_improper_model_uri_msg(uri, scheme))\n    path = parsed.path\n    if not path.startswith(\"/\") or len(path) <= 1:\n        raise MlflowException(_improper_model_uri_msg(uri, scheme))\n\n    parts = path.lstrip(\"/\").split(\"/\")\n    if len(parts) > 2 or parts[0].strip() == \"\":\n        raise MlflowException(_improper_model_uri_msg(uri, scheme))\n\n    if len(parts) == 2:\n        name, suffix = parts\n        if suffix.strip() == \"\":\n            raise MlflowException(_improper_model_uri_msg(uri, scheme))\n        # The URI is in the suffix format\n        if suffix.isdigit():\n            # The suffix is a specific version, e.g. \"models:/AdsModel1/123\"\n            return ParsedModelUri(name=name, version=suffix)\n        elif suffix.lower() == _MODELS_URI_SUFFIX_LATEST.lower() and scheme == \"models\":\n            # The suffix is the 'latest' string (case insensitive), e.g. \"models:/AdsModel1/latest\"","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/mlflow/mlflow/blob/6a27f2decc0b76eb1b54af31849784addb357dbc/mlflow/store/artifact/utils/models.py#L57-L93","documentation":"`_parse_model_uri` validates that a models:/ or prompts:/ URI has the expected scheme before parsing. If urlparse reports a different scheme (or none), MLflow raises this 'not a proper URI' MlflowException because the string cannot be a model/prompt reference at all.","triggerScenarios":"Passing a URI like 's3://bucket/model', a bare 'my-model' with no scheme, 'model:/name/1' (typo), or a Windows-style 'C:\\models\\x' to load_model / _parse_model_id_if_present / get_model_name_and_version when scheme='models' or 'prompts' is expected.","commonSituations":"Passing an artifact path or local directory where a models:/ URI is required; environment-specific config that injects a storage URI instead of a registry URI; forgetting the 'models:' prefix; double slashes like 'models://name/1' making the scheme parse differently.","solutions":["Prefix the reference with the correct scheme: 'models:/<name>/<version>' (or '@alias')","If you have a storage path, load it directly (mlflow.pyfunc.load_model accepts local paths and file:///s3:/ URIs) — don't wrap it in models:/","Check where the URI string comes from (config/env/DB) and validate it starts with 'models:/' before calling the API"],"exampleFix":"// before\nm = mlflow.pyfunc.load_model(\"prod-model\")\n// after\nm = mlflow.pyfunc.load_model(\"models:/prod-model@champion\")","handlingStrategy":"validation","validationCode":"def is_model_uri(u: str) -> bool:\n    return isinstance(u, str) and u.startswith(\"models:/\")","typeGuard":"def is_model_uri(u: object) -> bool:\n    return isinstance(u, str) and u.startswith(\"models:/\")","tryCatchPattern":"from mlflow.exceptions import MlflowException\ntry:\n    model = mlflow.pyfunc.load_model(uri)\nexcept MlflowException:\n    model = mlflow.pyfunc.load_model(artifact_uri)  # fallback to storage path","preventionTips":["Keep registry URIs (models:/...) and artifact/storage URIs in separate config fields","Assert scheme before calling model-loading APIs","Never interpolate storage paths into models:/ URIs"],"tags":["mlflow","uri","parsing","model-registry"],"backgroundTag":"invalid-uri-format","analyzedSha":"6a27f2decc0b76eb1b54af31849784addb357dbc","analyzedAt":"2026-08-29T20:54:51.419Z","schemaVersion":2},"datasetVersion":"2026-08-29T22:17:34.462Z"}