Repository: iterative/dvc

Issue:
`exp run:` `--dry` option fails experiment 
# Bug Report

<!--
## Issue name

Issue names must follow the pattern `command: description` where the command is the dvc command that you are trying to run. The description should describe the consequence of the bug.

Example: `repro: doesn't detect input changes`
-->

## Description

`dvc exp run --dry` causes the experiment to fail because of a reference to an undeclared variable.

### Reproduce

<!--
Step list of how to reproduce the bug
-->

I think it is just needed to execute `dvc exp run --dry`. However, I did `dvc exp run -s prepare-data-raw --dry` because other stages couldn't be executed -- a known error in my pipeline that I didn't solve yet because it is time-costly, but I will.

<!--
Example:

1. dvc init
2. Copy dataset.zip to the directory
3. dvc add dataset.zip
4. dvc run -d dataset.zip -o model ./train.sh
5. modify dataset.zip
6. dvc repro
-->



### Expected

All dependencies are checked and stages are pseudo-executed.

### Environment information

<!--
This is required to ensure that we can reproduce the bug.
-->

**Output of `dvc doctor`:**

```console
$ dvc doctor
DVC version: 2.41.1 (pip)
---------------------------------
Platform: Python 3.9.15 on Linux-6.1.1-arch1-1-x86_64-with-glibc2.36
Subprojects:
	dvc_data = 0.29.0
	dvc_objects = 0.14.1
	dvc_render = 0.0.17
	dvc_task = 0.1.9
	dvclive = 1.3.1
	scmrepo = 0.1.5
Supports:
	azure (adlfs = 2022.11.2, knack = 0.9.0, azure-identity = 1.10.0),
	gdrive (pydrive2 = 1.15.0),
	gs (gcsfs = 2022.11.0),
	hdfs (fsspec = 2022.11.0, pyarrow = 8.0.0),
	http (aiohttp = 3.8.1, aiohttp-retry = 2.5.2),
	https (aiohttp = 3.8.1, aiohttp-retry = 2.5.2),
	oss (ossfs = 2021.8.0),
	s3 (s3fs = 2022.11.0, boto3 = 1.24.59),
	ssh (sshfs = 2022.6.0),
	webdav (webdav4 = 0.9.7),
	webdavs (webdav4 = 0.9.7),
	webhdfs (fsspec = 2022.11.0)
Cache types: reflink, hardlink, symlink
Cache directory: btrfs on /dev/nvme0n1p3
Caches: local
Remotes: gdrive, ssh, ssh, ssh
Workspace directory: btrfs on /dev/nvme0n1p3
Repo: dvc, git
```

**Additional Information (if any):**

<!--
Please check https://github.com/iterative/dvc/wiki/Debugging-DVC on ways to gather more information regarding the issue.

If applicable, please also provide a `--verbose` output of the command, eg: `dvc add --verbose`.
If the issue is regarding the performance, please attach the profiling information and the benchmark comparisons.
-->

```
...
2023-01-16 20:38:08,542 DEBUG: stage: 'prepare-data-raw@cr-test' was reproduced
2023-01-16 20:38:08,545 DEBUG: Removing '/home/warley/dev/toledo/.dvc/tmp/exps/run/workspace'
2023-01-16 20:38:08,551 ERROR: Failed to reproduce experiment '424afed': local variable 'ref' referenced before assignment
------------------------------------------------------------
Traceback (most recent call last):
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/queue/workspace.py", line 115, in _reproduce_entry
    exec_result = executor.reproduce(
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/executor/base.py", line 500, in reproduce
    info.result_ref = ref
UnboundLocalError: local variable 'ref' referenced before assignment

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/cli/__init__.py", line 185, in main
    ret = cmd.do_run()
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/cli/command.py", line 22, in do_run
    return self.run()
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/commands/experiments/run.py", line 32, in run
    results = self.repo.experiments.run(
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/__init__.py", line 469, in run
    return run(self.repo, *args, **kwargs)
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/__init__.py", line 48, in wrapper
    return f(repo, *args, **kwargs)
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/run.py", line 59, in run
    return repo.experiments.reproduce_one(
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/__init__.py", line 113, in reproduce_one
    results = self._reproduce_queue(exp_queue)
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/utils.py", line 73, in wrapper
    ret = f(exp, *args, **kwargs)
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/__init__.py", line 353, in _reproduce_queue
    exec_results = queue.reproduce()
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/queue/workspace.py", line 91, in reproduce
    results.update(self._reproduce_entry(entry, executor))
  File "/home/warley/.virtualenvs/toledo/lib/python3.9/site-packages/dvc/repo/experiments/queue/workspace.py", line 138, in _reproduce_entry
    raise DvcException(
dvc.exceptions.DvcException: Failed to reproduce experiment '424afed'
```

The error seems to be on `dvc/repo/experiments/executor/base.py` (obvious from the traceback above)

```python
 488   │             exp_hash = cls.hash_exp(stages)
 489   │             if not repro_dry:
 490   │                 ref, exp_ref, repro_force = cls._repro_commit(
 491   │                     dvc,
 492   │                     info,
 493   │                     stages,
 494   │                     exp_hash,
 495   │                     auto_push,
 496   │                     git_remote,
 497   │                     repro_force,
 498   │                 )
 499   │             info.result_hash = exp_hash
 500   │             info.result_ref = ref
 501   │             info.result_force = repro_force
```


Discussion:
Hi @vitalwarley , thanks for the detailed report. I can reproduce it.
Taking a look

Resolving patch:
diff --git a/dvc/repo/experiments/executor/base.py b/dvc/repo/experiments/executor/base.py
--- a/dvc/repo/experiments/executor/base.py
+++ b/dvc/repo/experiments/executor/base.py
@@ -499,9 +499,9 @@ def filter_pipeline(stages):
                     git_remote,
                     repro_force,
                 )
-            info.result_hash = exp_hash
-            info.result_ref = ref
-            info.result_force = repro_force
+                info.result_hash = exp_hash
+                info.result_ref = ref
+                info.result_force = repro_force
 
         # ideally we would return stages here like a normal repro() call, but
         # stages is not currently picklable and cannot be returned across


Test patch:
diff --git a/tests/func/experiments/test_experiments.py b/tests/func/experiments/test_experiments.py
--- a/tests/func/experiments/test_experiments.py
+++ b/tests/func/experiments/test_experiments.py
@@ -748,3 +748,9 @@ def test_experiment_unchanged(tmp_dir, scm, dvc, exp_stage):
     dvc.experiments.run(exp_stage.addressing)
 
     assert len(dvc.experiments.ls()["master"]) == 2
+
+
+def test_experiment_run_dry(tmp_dir, scm, dvc, exp_stage):
+    dvc.experiments.run(exp_stage.addressing, dry=True)
+
+    assert len(dvc.experiments.ls()["master"]) == 0