# Choose the right PennyLane diff_method and fix gradient configuration errors

Fix PennyLane gradient failures by matching the exact error (parameter-shift vs state, backprop vs shots, adjoint vs measurement, broadcasted tapes, device jacobian) to the illegal configuration, then pick diff_method from a device x shots x measurement matrix.

Exact reference: {"kind":"skill_version","skill_id":"skl_L4IdBc2fm_z1BWeWZ16ZgA","version_id":"skv_xv9lmpxbnN0J-cIOuPoRkg"}

Applicability: [{"constraint":">=0.40","technology":"PennyLane","version_scheme":"semver"}]

# Choose the right diff_method and fix gradient configuration errors in PennyLane

Use this when a PennyLane gradient call raises `QuantumFunctionError`,
`ValueError`, or `NotImplementedError` naming the differentiation method, or when
you are choosing `diff_method` for a new QNode. The error message names the
illegal combination directly — match it before changing anything.

## 1. Read the exact error — it names the illegal combination

| Error text | Meaning | Fix |
|---|---|---|
| `Computing the gradient of circuits that return the state with the parameter-shift rule gradient transform is not supported, as it is a hardware-compatible method.` | `diff_method="parameter-shift"` on a circuit returning `qml.state()` (or `qml.density_matrix`) | On a simulator with `shots=None`, switch to `diff_method="backprop"`; or return `qml.expval` instead of the state |
| `QuantumFunctionError: Backpropagation is only supported when shots=None.` | `diff_method="backprop"` with finite shots | Set `shots=None` on the device, or switch to `diff_method="parameter-shift"` |
| `QuantumFunctionError: Adjoint differentiation method does not support measurement state` | `diff_method="adjoint"` on a circuit returning `qml.state()` | Adjoint only supports expectation values of observables; use `"backprop"` or change the measurement |
| `NotImplementedError: Computing the gradient of broadcasted tapes with respect to the broadcasted parameters using the parameter-shift rule gradient transform is currently not supported.` | A trainable parameter is broadcast (e.g. one RX over a batch of angles) under parameter-shift | Do not make the broadcast axis trainable: loop over the batch in Python, or use `"backprop"` on a simulator |
| `QuantumFunctionError: Device <...> does not support device with requested circuit.` | `diff_method="device"` on a device with no native jacobian (e.g. `default.qubit`) | Use `"best"`, `"backprop"`, `"adjoint"`, or `"parameter-shift"` instead — `"device"` needs a device that provides its own jacobian |

## 2. Pick diff_method from device x shots x measurement

Classify your configuration first; the matrix below gives the method:

- **Simulator** (`default.qubit`, `lightning.qubit`) + `shots=None` + `qml.expval`/`qml.var`/`qml.probs`: `diff_method="best"` (the default) resolves to backprop on `default.qubit` — exact and usually cheapest. Use `"adjoint"` when the parameter count is large (much lower memory, similar runtime). Both are simulator-only.
- **Simulator + finite shots** (`shots=1000`, etc.): only hardware-compatible methods work — `"parameter-shift"`, `"finite-diff"`, `"hadamard"`. Backprop raises the `shots=None` error; adjoint warns and computes the gradient analytically anyway, so the gradient no longer matches the noisy forward pass.
- **Hardware device**: only `"parameter-shift"`, `"finite-diff"`, or `"hadamard"`. Backprop and adjoint are never available — this is documented, not a bug.
- **Circuit returns `qml.state()`**: only `"backprop"` on a simulator with `shots=None`. Parameter-shift and adjoint both refuse (see the error table). Never on hardware.
- **Circuit returns `qml.sample` or `qml.counts`**: no gradient under any method or device. The QNode must return `qml.expval` (or `qml.probs`) to train.

## 3. Know the cost before you pick

Parameter-shift needs 2 circuit evaluations per trainable parameter per gradient
step, so gradient cost scales linearly with parameter count. On simulators,
backprop and adjoint are usually cheaper and exact — prefer them whenever the
configuration in step 2 allows. Finite shots make parameter-shift gradients
noisy estimators; that is expected, not a bug.

## 4. Checklist for the failing gradient call

1. Copy the full error text; match it to the table in step 1.
2. Confirm the three facts: device class (simulator vs hardware), `shots`
   setting (`None` vs finite), and the returned measurement type.
3. Apply the method from step 2's matrix — not the one that worked in a
   tutorial with a different configuration.
4. Re-run the gradient call (`qml.grad(circuit)(params)` or the interface's
   backward pass) and confirm the error is gone before tuning anything else.


## Supporting basis and limitations

Built from the PennyLane docs (interfaces guide: backprop/adjoint are simulator-only, parameter-shift/finite-diff/hadamard are hardware-compatible), the doc/introduction/unsupported_gradients.rst page (exact QuantumFunctionError texts for backprop-with-shots, adjoint-with-state, and device-jacobian), and recurring discuss.pennylane.ai threads (parameter-shift rule is hardware-compatible so it cannot differentiate qml.state(); broadcasted-tape parameter-shift limitation).

## Change and rationale

New skill: choose the right PennyLane diff_method and fix gradient configuration errors.

Most PennyLane gradient questions on the forum are configuration errors, not math errors: parameter-shift on qml.state(), backprop with finite shots, adjoint on state measurements, or backprop on hardware. The error messages name the illegal combination but users still guess. This skill adds a decision procedure: match the error text first, then select diff_method from device, shots, and measurement type.
