Repository: mlflow/mlflow

Issue:
[BUG] 1.30: mlflow.exceptions.RestException: BAD_REQUEST: (sqlite3.IntegrityError) UNIQUE constraint failed: tags.key, tags.run_uuid
### Issues Policy acknowledgement

- [X] I have read and agree to submit bug reports in accordance with the [issues policy](https://www.github.com/mlflow/mlflow/blob/master/ISSUE_POLICY.md)

### Willingness to contribute

No. I cannot contribute a bug fix at this time.

### MLflow version

1.30

### System information

- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**: ubuntu 20.04
- **Python version**: 3.9.15
- **yarn version, if running the dev UI**:


### Describe the problem

After starting version 1.30 via:

mlflow server -h 0.0.0.0 -p 5050 \
  --backend-store-uri sqlite:////home/mlflow/mlflow.db \
  --serve-artifacts \
  --artifacts-destination file:/home/mlflow/mlartifacts

on a fresh install, I get:

mlflow.exceptions.RestException: BAD_REQUEST: (sqlite3.IntegrityError) UNIQUE constraint failed: tags.key, tags.run_uuid




### Tracking information

>>> import mlflow
>>> print("MLflow version:", mlflow.__version__)
MLflow version: 1.30.0
>>> print("Tracking URI:", mlflow.get_tracking_uri())
Tracking URI: file:///home/mlflow/mlruns
>>> print("Artifact URI:", mlflow.get_artifact_uri())
Artifact URI: file:///home/mlflow/mlruns/0/78c1349a05df4b7aada9a7f05bccd26e/artifacts


### Code to reproduce issue

with mlflow.start_run(**kwargs) as run:
  ...

### Stack trace

  File "/home/kaina/work/repo/core/scripts/tfx/mlflow_continuation_example.py", line 151, in do_run
    with mlflow.start_run(**kwargs) as run:
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/tracking/fluent.py", line 318, in start_run
    active_run_obj = client.create_run(experiment_id=exp_id_for_run, tags=resolved_tags)
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/tracking/client.py", line 265, in create_run
    return self._tracking_client.create_run(experiment_id, start_time, tags)
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/tracking/_tracking_service/client.py", line 99, in create_run
    return self.store.create_run(
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/store/tracking/rest_store.py", line 170, in create_run
    response_proto = self._call_endpoint(CreateRun, req_body)
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/store/tracking/rest_store.py", line 56, in _call_endpoint
    return call_endpoint(self.get_host_creds(), endpoint, method, json_body, response_proto)
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/utils/rest_utils.py", line 256, in call_endpoint
    response = verify_rest_response(response, endpoint)
  File "/home/kaina/.pyenv/versions/core/lib/python3.9/site-packages/mlflow/utils/rest_utils.py", line 185, in verify_rest_response
    raise RestException(json.loads(response.text))
mlflow.exceptions.RestException: BAD_REQUEST: (sqlite3.IntegrityError) UNIQUE constraint failed: tags.key, tags.run_uuid
[SQL: INSERT INTO tags ("key", value, run_uuid) VALUES (?, ?, ?)]


### Other info / logs

_No response_

### What component(s) does this bug affect?

- [ ] `area/artifacts`: Artifact stores and artifact logging
- [ ] `area/build`: Build and test infrastructure for MLflow
- [ ] `area/docs`: MLflow documentation pages
- [ ] `area/examples`: Example code
- [ ] `area/model-registry`: Model Registry service, APIs, and the fluent client calls for Model Registry
- [ ] `area/models`: MLmodel format, model serialization/deserialization, flavors
- [ ] `area/pipelines`: Pipelines, Pipeline APIs, Pipeline configs, Pipeline Templates
- [ ] `area/projects`: MLproject format, project running backends
- [ ] `area/scoring`: MLflow Model server, model deployment tools, Spark UDFs
- [ ] `area/server-infra`: MLflow Tracking server backend
- [X] `area/tracking`: Tracking Service, tracking client APIs, autologging

### What interface(s) does this bug affect?

- [ ] `area/uiux`: Front-end, user experience, plotting, JavaScript, JavaScript dev server
- [ ] `area/docker`: Docker use across MLflow's components, such as MLflow Projects and MLflow Models
- [ ] `area/sqlalchemy`: Use of SQLAlchemy in the Tracking Service or Model Registry
- [ ] `area/windows`: Windows support

### What language(s) does this bug affect?

- [ ] `language/r`: R APIs and clients
- [ ] `language/java`: Java APIs and clients
- [ ] `language/new`: Proposals for new client languages

### What integration(s) does this bug affect?

- [ ] `integrations/azure`: Azure and Azure ML integrations
- [ ] `integrations/sagemaker`: SageMaker integrations
- [ ] `integrations/databricks`: Databricks integrations


Discussion:
@alexanderkainsky I ran:

```
docker run --rm -e MLFLOW_TRACKING_URI=sqlite:///mlflow.db python:3.8 bash -c "pip install mlflow && python -c 'import mlflow; mlflow.start_run()'"
```

but wasn't able to reproduce the issue.


Output:

```
Collecting mlflow
  Downloading mlflow-1.30.0-py3-none-any.whl (17.0 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.0/17.0 MB 11.0 MB/s eta 0:00:00
Collecting packaging<22
  Downloading packaging-21.3-py3-none-any.whl (40 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.8/40.8 KB 8.5 MB/s eta 0:00:00
Collecting docker<7,>=4.0.0
  Downloading docker-6.0.0-py3-none-any.whl (147 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 147.2/147.2 KB 10.2 MB/s eta 0:00:00
Collecting importlib-metadata!=4.7.0,<6,>=3.7.0
  Downloading importlib_metadata-5.0.0-py3-none-any.whl (21 kB)
Collecting requests<3,>=2.17.3
  Downloading requests-2.28.1-py3-none-any.whl (62 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.8/62.8 KB 8.7 MB/s eta 0:00:00
Collecting sqlalchemy<2,>=1.4.0
  Downloading SQLAlchemy-1.4.42-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.6/1.6 MB 11.1 MB/s eta 0:00:00
Collecting Flask<3
  Downloading Flask-2.2.2-py3-none-any.whl (101 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 101.5/101.5 KB 10.0 MB/s eta 0:00:00
Collecting gunicorn<21
  Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79.5/79.5 KB 9.3 MB/s eta 0:00:00
Collecting pandas<2
  Downloading pandas-1.5.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.2/12.2 MB 11.1 MB/s eta 0:00:00
Collecting pyyaml<7,>=5.1
  Downloading PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (701 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 701.2/701.2 KB 11.0 MB/s eta 0:00:00
Collecting protobuf<5,>=3.12.0
  Downloading protobuf-4.21.8-cp37-abi3-manylinux2014_x86_64.whl (408 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 408.4/408.4 KB 10.9 MB/s eta 0:00:00
Collecting pytz<2023
  Downloading pytz-2022.5-py2.py3-none-any.whl (500 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 500.7/500.7 KB 11.0 MB/s eta 0:00:00
Collecting prometheus-flask-exporter<1
  Downloading prometheus_flask_exporter-0.20.3-py3-none-any.whl (18 kB)
Collecting sqlparse<1,>=0.4.0
  Downloading sqlparse-0.4.3-py3-none-any.whl (42 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.8/42.8 KB 8.3 MB/s eta 0:00:00
Collecting gitpython<4,>=2.1.0
  Downloading GitPython-3.1.29-py3-none-any.whl (182 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 182.5/182.5 KB 10.5 MB/s eta 0:00:00
Collecting querystring-parser<2
  Downloading querystring_parser-1.2.4-py2.py3-none-any.whl (7.9 kB)
Collecting alembic<2
  Downloading alembic-1.8.1-py3-none-any.whl (209 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 209.8/209.8 KB 10.5 MB/s eta 0:00:00
Collecting scipy<2
  Downloading scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (33.8 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 33.8/33.8 MB 10.7 MB/s eta 0:00:00
Collecting click<9,>=7.0
  Downloading click-8.1.3-py3-none-any.whl (96 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 96.6/96.6 KB 9.4 MB/s eta 0:00:00
Collecting databricks-cli<1,>=0.8.7
  Downloading databricks-cli-0.17.3.tar.gz (77 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77.9/77.9 KB 9.6 MB/s eta 0:00:00
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Collecting entrypoints<1
  Downloading entrypoints-0.4-py3-none-any.whl (5.3 kB)
Collecting numpy<2
  Downloading numpy-1.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.1/17.1 MB 11.0 MB/s eta 0:00:00
Collecting cloudpickle<3
  Downloading cloudpickle-2.2.0-py3-none-any.whl (25 kB)
Collecting Mako
  Downloading Mako-1.2.3-py3-none-any.whl (78 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78.7/78.7 KB 9.6 MB/s eta 0:00:00
Collecting importlib-resources
  Downloading importlib_resources-5.10.0-py3-none-any.whl (34 kB)
Collecting pyjwt>=1.7.0
  Downloading PyJWT-2.6.0-py3-none-any.whl (20 kB)
Collecting oauthlib>=3.1.0
  Downloading oauthlib-3.2.2-py3-none-any.whl (151 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 151.7/151.7 KB 9.7 MB/s eta 0:00:00
Collecting tabulate>=0.7.7
  Downloading tabulate-0.9.0-py3-none-any.whl (35 kB)
Collecting six>=1.10.0
  Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting websocket-client>=0.32.0
  Downloading websocket_client-1.4.1-py3-none-any.whl (55 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 55.0/55.0 KB 8.8 MB/s eta 0:00:00
Collecting urllib3>=1.26.0
  Downloading urllib3-1.26.12-py2.py3-none-any.whl (140 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 140.4/140.4 KB 10.3 MB/s eta 0:00:00
Collecting itsdangerous>=2.0
  Downloading itsdangerous-2.1.2-py3-none-any.whl (15 kB)
Collecting Werkzeug>=2.2.2
  Downloading Werkzeug-2.2.2-py3-none-any.whl (232 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 232.7/232.7 KB 10.6 MB/s eta 0:00:00
Collecting Jinja2>=3.0
  Downloading Jinja2-3.1.2-py3-none-any.whl (133 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.1/133.1 KB 10.2 MB/s eta 0:00:00
Collecting gitdb<5,>=4.0.1
  Downloading gitdb-4.0.9-py3-none-any.whl (63 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.1/63.1 KB 8.9 MB/s eta 0:00:00
Requirement already satisfied: setuptools>=3.0 in /usr/local/lib/python3.8/site-packages (from gunicorn<21->mlflow) (57.5.0)
Collecting zipp>=0.5
  Downloading zipp-3.9.0-py3-none-any.whl (5.8 kB)
Collecting pyparsing!=3.0.5,>=2.0.2
  Downloading pyparsing-3.0.9-py3-none-any.whl (98 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 98.3/98.3 KB 9.8 MB/s eta 0:00:00
Collecting python-dateutil>=2.8.1
  Downloading python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 247.7/247.7 KB 10.7 MB/s eta 0:00:00
Collecting prometheus-client
  Downloading prometheus_client-0.15.0-py3-none-any.whl (60 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.1/60.1 KB 8.5 MB/s eta 0:00:00
Collecting charset-normalizer<3,>=2
  Downloading charset_normalizer-2.1.1-py3-none-any.whl (39 kB)
Collecting certifi>=2017.4.17
  Downloading certifi-2022.9.24-py3-none-any.whl (161 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 161.1/161.1 KB 10.4 MB/s eta 0:00:00
Collecting idna<4,>=2.5
  Downloading idna-3.4-py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.5/61.5 KB 8.6 MB/s eta 0:00:00
Collecting greenlet!=0.4.17
  Downloading greenlet-1.1.3.post0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (157 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 157.4/157.4 KB 10.3 MB/s eta 0:00:00
Collecting smmap<6,>=3.0.1
  Downloading smmap-5.0.0-py3-none-any.whl (24 kB)
Collecting MarkupSafe>=2.0
  Downloading MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (25 kB)
Building wheels for collected packages: databricks-cli
  Building wheel for databricks-cli (setup.py): started
  Building wheel for databricks-cli (setup.py): finished with status 'done'
  Created wheel for databricks-cli: filename=databricks_cli-0.17.3-py3-none-any.whl size=139102 sha256=b2e6fd98ab2aef323bb2072811e14dbc963df21031e6d341f95912ea26760908
  Stored in directory: /root/.cache/pip/wheels/58/40/7c/d021d51dac18bfd095fb6837572ad2e6f1a34d221f4b1d976b
Successfully built databricks-cli
Installing collected packages: pytz, zipp, websocket-client, urllib3, tabulate, sqlparse, smmap, six, pyyaml, pyparsing, pyjwt, protobuf, prometheus-client, oauthlib, numpy, MarkupSafe, itsdangerous, idna, gunicorn, greenlet, entrypoints, cloudpickle, click, charset-normalizer, certifi, Werkzeug, sqlalchemy, scipy, requests, querystring-parser, python-dateutil, packaging, Mako, Jinja2, importlib-resources, importlib-metadata, gitdb, pandas, gitpython, Flask, docker, databricks-cli, alembic, prometheus-flask-exporter, mlflow
Successfully installed Flask-2.2.2 Jinja2-3.1.2 Mako-1.2.3 MarkupSafe-2.1.1 Werkzeug-2.2.2 alembic-1.8.1 certifi-2022.9.24 charset-normalizer-2.1.1 click-8.1.3 cloudpickle-2.2.0 databricks-cli-0.17.3 docker-6.0.0 entrypoints-0.4 gitdb-4.0.9 gitpython-3.1.29 greenlet-1.1.3.post0 gunicorn-20.1.0 idna-3.4 importlib-metadata-5.0.0 importlib-resources-5.10.0 itsdangerous-2.1.2 mlflow-1.30.0 numpy-1.23.4 oauthlib-3.2.2 packaging-21.3 pandas-1.5.1 prometheus-client-0.15.0 prometheus-flask-exporter-0.20.3 protobuf-4.21.8 pyjwt-2.6.0 pyparsing-3.0.9 python-dateutil-2.8.2 pytz-2022.5 pyyaml-6.0 querystring-parser-1.2.4 requests-2.28.1 scipy-1.9.3 six-1.16.0 smmap-5.0.0 sqlalchemy-1.4.42 sqlparse-0.4.3 tabulate-0.9.0 urllib3-1.26.12 websocket-client-1.4.1 zipp-3.9.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
WARNING: You are using pip version 22.0.4; however, version 22.3 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.
2022/10/22 01:07:56 INFO mlflow.store.db.utils: Creating initial MLflow database tables...
2022/10/22 01:07:56 INFO mlflow.store.db.utils: Updating database tables
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 451aebb31d03, add metric step
INFO  [alembic.runtime.migration] Running upgrade 451aebb31d03 -> 90e64c465722, migrate user column to tags
INFO  [alembic.runtime.migration] Running upgrade 90e64c465722 -> 181f10493468, allow nulls for metric values
INFO  [alembic.runtime.migration] Running upgrade 181f10493468 -> df50e92ffc5e, Add Experiment Tags Table
INFO  [alembic.runtime.migration] Running upgrade df50e92ffc5e -> 7ac759974ad8, Update run tags with larger limit
INFO  [alembic.runtime.migration] Running upgrade 7ac759974ad8 -> 89d4b8295536, create latest metrics table
INFO  [89d4b8295536_create_latest_metrics_table_py] Migration complete!
INFO  [alembic.runtime.migration] Running upgrade 89d4b8295536 -> 2b4d017a5e9b, add model registry tables to db
INFO  [2b4d017a5e9b_add_model_registry_tables_to_db_py] Adding registered_models and model_versions tables to database.
INFO  [2b4d017a5e9b_add_model_registry_tables_to_db_py] Migration complete!
INFO  [alembic.runtime.migration] Running upgrade 2b4d017a5e9b -> cfd24bdc0731, Update run status constraint with killed
INFO  [alembic.runtime.migration] Running upgrade cfd24bdc0731 -> 0a8213491aaa, drop_duplicate_killed_constraint
INFO  [alembic.runtime.migration] Running upgrade 0a8213491aaa -> 728d730b5ebd, add registered model tags table
INFO  [alembic.runtime.migration] Running upgrade 728d730b5ebd -> 27a6a02d2cf1, add model version tags table
INFO  [alembic.runtime.migration] Running upgrade 27a6a02d2cf1 -> 84291f40a231, add run_link to model_version
INFO  [alembic.runtime.migration] Running upgrade 84291f40a231 -> a8c4a736bde6, allow nulls for run_id
INFO  [alembic.runtime.migration] Running upgrade a8c4a736bde6 -> 39d1c3be5f05, add_is_nan_constraint_for_metrics_tables_if_necessary
INFO  [alembic.runtime.migration] Running upgrade 39d1c3be5f05 -> c48cb773bb87, reset_default_value_for_is_nan_in_metrics_table_for_mysql
INFO  [alembic.runtime.migration] Running upgrade c48cb773bb87 -> bd07f7e963c5, create index on run_uuid
INFO  [alembic.runtime.migration] Running upgrade bd07f7e963c5 -> 0c779009ac13, add deleted_time field to runs table
INFO  [alembic.runtime.migration] Running upgrade 0c779009ac13 -> cc1f77228345, change param value length to 500
INFO  [alembic.runtime.migration] Running upgrade cc1f77228345 -> 97727af70f4d, Add creation_time and last_update_time to experiments table
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
```
Look like you pass `kwargs` to `mlflow.start_run`. Can you share the value of `kwargs`?

Resolving patch:
diff --git a/mlflow/store/tracking/file_store.py b/mlflow/store/tracking/file_store.py
--- a/mlflow/store/tracking/file_store.py
+++ b/mlflow/store/tracking/file_store.py
@@ -604,7 +604,17 @@ def create_run(self, experiment_id, user_id, start_time, tags, run_name):
                 "Could not create run under non-active experiment with ID %s." % experiment_id,
                 databricks_pb2.INVALID_STATE,
             )
-        run_name = run_name if run_name else _generate_random_name()
+        tags = tags or []
+        run_name_tag = _get_run_name_from_tags(tags)
+        if run_name and run_name_tag:
+            raise MlflowException(
+                "Both 'run_name' argument and 'mlflow.runName' tag are specified. "
+                "Remove 'mlflow.runName' tag.",
+                INVALID_PARAMETER_VALUE,
+            )
+        run_name = run_name or run_name_tag or _generate_random_name()
+        if not run_name_tag:
+            tags.append(RunTag(key=MLFLOW_RUN_NAME, value=run_name))
         run_uuid = uuid.uuid4().hex
         artifact_uri = self._get_artifact_dir(experiment_id, run_uuid)
         run_info = RunInfo(
@@ -628,8 +638,6 @@ def create_run(self, experiment_id, user_id, start_time, tags, run_name):
         mkdir(run_dir, FileStore.METRICS_FOLDER_NAME)
         mkdir(run_dir, FileStore.PARAMS_FOLDER_NAME)
         mkdir(run_dir, FileStore.ARTIFACTS_FOLDER_NAME)
-        tags = tags or []
-        tags.append(RunTag(MLFLOW_RUN_NAME, run_name))
         for tag in tags:
             self.set_tag(run_uuid, tag)
         return self.get_run(run_id=run_uuid)
diff --git a/mlflow/store/tracking/sqlalchemy_store.py b/mlflow/store/tracking/sqlalchemy_store.py
--- a/mlflow/store/tracking/sqlalchemy_store.py
+++ b/mlflow/store/tracking/sqlalchemy_store.py
@@ -57,7 +57,7 @@
     _validate_param,
     _validate_experiment_name,
 )
-from mlflow.utils.mlflow_tags import MLFLOW_LOGGED_MODELS, MLFLOW_RUN_NAME
+from mlflow.utils.mlflow_tags import MLFLOW_LOGGED_MODELS, MLFLOW_RUN_NAME, _get_run_name_from_tags
 from mlflow.utils.time_utils import get_current_time_millis
 
 _logger = logging.getLogger(__name__)
@@ -548,7 +548,17 @@ def create_run(self, experiment_id, user_id, start_time, tags, run_name):
             artifact_location = append_to_uri_path(
                 experiment.artifact_location, run_id, SqlAlchemyStore.ARTIFACTS_FOLDER_NAME
             )
-            run_name = run_name if run_name else _generate_random_name()
+            tags = tags or []
+            run_name_tag = _get_run_name_from_tags(tags)
+            if run_name and run_name_tag:
+                raise MlflowException(
+                    "Both 'run_name' argument and 'mlflow.runName' tag are specified. "
+                    "Remove 'mlflow.runName' tag.",
+                    INVALID_PARAMETER_VALUE,
+                )
+            run_name = run_name or run_name_tag or _generate_random_name()
+            if not run_name_tag:
+                tags.append(RunTag(key=MLFLOW_RUN_NAME, value=run_name))
             run = SqlRun(
                 name=run_name,
                 artifact_uri=artifact_location,
@@ -566,8 +576,6 @@ def create_run(self, experiment_id, user_id, start_time, tags, run_name):
                 lifecycle_stage=LifecycleStage.ACTIVE,
             )
 
-            tags = tags or []
-            tags.append(RunTag(key=MLFLOW_RUN_NAME, value=run_name))
             run.tags = [SqlTag(key=tag.key, value=tag.value) for tag in tags]
             self._save_to_db(objs=run, session=session)
 


Test patch:
diff --git a/tests/store/tracking/test_file_store.py b/tests/store/tracking/test_file_store.py
--- a/tests/store/tracking/test_file_store.py
+++ b/tests/store/tracking/test_file_store.py
@@ -8,6 +8,7 @@
 import unittest
 import uuid
 from pathlib import Path
+import re
 
 import pytest
 from unittest import mock
@@ -819,6 +820,28 @@ def test_create_run_sets_name(self):
         assert run.info.run_name == "my name"
         assert run.data.tags.get(MLFLOW_RUN_NAME) == "my name"
 
+        run_id = fs.create_run(
+            experiment_id=FileStore.DEFAULT_EXPERIMENT_ID,
+            user_id="user",
+            start_time=0,
+            run_name=None,
+            tags=[RunTag(MLFLOW_RUN_NAME, "test")],
+        ).info.run_id
+        run = fs.get_run(run_id)
+        assert run.info.run_name == "test"
+
+        with pytest.raises(
+            MlflowException,
+            match=re.escape("Both 'run_name' argument and 'mlflow.runName' tag are specified."),
+        ):
+            fs.create_run(
+                experiment_id=FileStore.DEFAULT_EXPERIMENT_ID,
+                user_id="user",
+                start_time=0,
+                run_name="test",
+                tags=[RunTag(MLFLOW_RUN_NAME, "test")],
+            )
+
     def _experiment_id_edit_func(self, old_dict):
         old_dict["experiment_id"] = int(old_dict["experiment_id"])
         return old_dict
diff --git a/tests/store/tracking/test_sqlalchemy_store.py b/tests/store/tracking/test_sqlalchemy_store.py
--- a/tests/store/tracking/test_sqlalchemy_store.py
+++ b/tests/store/tracking/test_sqlalchemy_store.py
@@ -2,6 +2,7 @@
 import shutil
 import tempfile
 import unittest
+import re
 
 import math
 import random
@@ -906,6 +907,27 @@ def test_create_run_sets_name(self):
         run = self.store.get_run(run_id)
         self.assertEqual(run.info.run_name, configs["run_name"])
         self.assertEqual(run.data.tags.get(mlflow_tags.MLFLOW_RUN_NAME), configs["run_name"])
+        run_id = self.store.create_run(
+            experiment_id=experiment_id,
+            user_id="user",
+            start_time=0,
+            run_name=None,
+            tags=[RunTag(mlflow_tags.MLFLOW_RUN_NAME, "test")],
+        ).info.run_id
+        run = self.store.get_run(run_id)
+        assert run.info.run_name == "test"
+
+        with pytest.raises(
+            MlflowException,
+            match=re.escape("Both 'run_name' argument and 'mlflow.runName' tag are specified."),
+        ):
+            self.store.create_run(
+                experiment_id=experiment_id,
+                user_id="user",
+                start_time=0,
+                run_name="test",
+                tags=[RunTag(mlflow_tags.MLFLOW_RUN_NAME, "test")],
+            )
 
     def test_get_run_with_name(self):
         experiment_id = self._experiment_factory("test_get_run")