Repository: Qiskit/qiskit

Issue:
specifying nonexistent synthesis plugin does not raise error
### Environment

- **Qiskit Terra version**: 0.45.1
- **Python version**: 3.10.12
- **Operating system**: Arch Linux


### What is happening?

`generate_preset_pass_manager` does not raise an error for a nonexistent synthesis plugin, even though it does for a nonexistent stage plugin.

### How can we reproduce the issue?

```python
from qiskit.providers.fake_provider import FakeBelem
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

backend = FakeBelem()
pass_manager = generate_preset_pass_manager(
    optimization_level=3, backend=backend, unitary_synthesis_method="a"
)
```

### What should happen?

This does not raise an error. Instead, an error is raised when the pass manager is run. This is inconsistent with the transpiler stage plugins. For example, this raises an error:
```python
from qiskit.providers.fake_provider import FakeBelem
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

backend = FakeBelem()
pass_manager = generate_preset_pass_manager(
    optimization_level=3, backend=backend, routing_method="a"
)
```
```
TranspilerError: 'Invalid plugin name a for stage routing'
```

### Any suggestions?

The error should be raised when the pass manager is created, not when it is run.


Discussion:
Can you assign me to this? 
I was playing around with `generate_preset_pass_manager` and couldn't find a way to do unitary synthesis this way. For example:

```python
from qiskit.providers.fake_provider import FakeBelem
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

backend = FakeBelem()
pass_manager = generate_preset_pass_manager(
    optimization_level=3, backend=backend, unitary_synthesis_method="aqc"
)
pass_manager.run(matrix)
```
Throws errors complaining that basically say `matrix` is not a `QuantumCircuit`. It queries methods like `name`, `global_phase`, and `calibrations`. How to use a pass manager or essentially `qiskit.transpile` to do unitary synthesis?
The input to `.run()` is a `QuantumCircuit` object, so you'll need to put the matrix on a circuit for the transpiler to work with it. The easiest way is to do something like:

```python
qc = QuantumCircuit(num_qubits)
qc.unitary(matrix, range(num_qubits))
```
and then pass qc to `.run()`.

The other option is to manually call the aqc synthesis directly. There is a code sample on how to do this here: https://docs.quantum.ibm.com/api/qiskit/synthesis_aqc but it's much more manual.

To solve the original issue we just need to add a check to `UnitarySynthesis`'s `__init__` method that the user specified plugin is valid. Right now it only gets checked during `UnitarySynthesis.run` which is why it doesn't error until the passmanager is run.

Resolving patch:
diff --git a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py
--- a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py
+++ b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py
@@ -331,6 +331,11 @@ def __init__(
             target: The optional :class:`~.Target` for the target device the pass
                 is compiling for. If specified this will supersede the values
                 set for ``basis_gates``, ``coupling_map``, and ``backend_props``.
+
+        Raises:
+            TranspilerError: if ``method`` was specified but is not found in the
+                installed plugins list. The list of installed plugins can be queried with
+                :func:`~qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names`
         """
         super().__init__()
         self._basis_gates = set(basis_gates or ())
@@ -358,6 +363,9 @@ def __init__(
 
         self._synth_gates = set(self._synth_gates) - self._basis_gates
 
+        if self.method != "default" and self.method not in self.plugins.ext_plugins:
+            raise TranspilerError(f"Specified method '{self.method}' not found in plugin list")
+
     def run(self, dag: DAGCircuit) -> DAGCircuit:
         """Run the UnitarySynthesis pass on ``dag``.
 
@@ -366,15 +374,7 @@ def run(self, dag: DAGCircuit) -> DAGCircuit:
 
         Returns:
             Output dag with UnitaryGates synthesized to target basis.
-
-        Raises:
-            TranspilerError: if ``method`` was specified for the class and is not
-                found in the installed plugins list. The list of installed
-                plugins can be queried with
-                :func:`~qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names`
         """
-        if self.method != "default" and self.method not in self.plugins.ext_plugins:
-            raise TranspilerError("Specified method: %s not found in plugin list" % self.method)
 
         # If there aren't any gates to synthesize in the circuit we can skip all the iteration
         # and just return.


Test patch:
diff --git a/test/python/transpiler/test_stage_plugin.py b/test/python/transpiler/test_stage_plugin.py
--- a/test/python/transpiler/test_stage_plugin.py
+++ b/test/python/transpiler/test_stage_plugin.py
@@ -22,6 +22,7 @@
 from qiskit.compiler.transpiler import transpile
 from qiskit.test import QiskitTestCase
 from qiskit.transpiler import PassManager, PassManagerConfig, CouplingMap
+from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
 from qiskit.transpiler.preset_passmanagers.builtin_plugins import BasicSwapPassManager
 from qiskit.transpiler.preset_passmanagers.plugin import (
     PassManagerStagePluginManager,
@@ -113,3 +114,16 @@ def test_routing_plugins(self, optimization_level, routing_method):
         backend = QasmSimulatorPy()
         counts = backend.run(tqc, shots=1000).result().get_counts()
         self.assertDictAlmostEqual(counts, {"0000": 500, "1111": 500}, delta=100)
+
+    @combine(
+        optimization_level=list(range(4)),
+    )
+    def test_unitary_synthesis_plugins(self, optimization_level):
+        """Test unitary synthesis plugins"""
+        backend = QasmSimulatorPy()
+        with self.assertRaises(TranspilerError):
+            _ = generate_preset_pass_manager(
+                optimization_level=optimization_level,
+                backend=backend,
+                unitary_synthesis_method="not a method",
+            )