> ## Content Index
> Fetch the complete content index at: https://tuguidragos.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Six defects in a verified n8n node for IBM Quantum
- URL: https://tuguidragos.com/six-defects-verified-n8n-node-ibm-quantum/
- Published: 2026-08-02T17:04:15.000Z
- Updated: 2026-09-13T18:42:29.000Z
- Description: It passed n8n verification with green tests and 98 percent coverage. Then 121 seconds of real QPU time found what none of that could.
- Author: Tugui Dragos
- Tags: Milestones, IBM Quantum, n8n, Quantum Computing, Automation, Debugging, Building, Open Source

The error told me my circuit contained a gate my circuit did not contain.

```
Failed to execute program: 'Circuit 0: The instruction u on qubits (1,) is not
supported by the target system. -- Transpile your circuits for the target before
submitting a primitive query. reason_code: 1517

```

I read it three times. There was no `u` anywhere in that circuit. I had built it deliberately out of the gates `ibm_kingston` reports as its own native set, which is the whole point of an ISA circuit, and the machine was refusing an instruction I had never written.

That was the start of eight hours that turned up six defects in my IBM Quantum node for n8n, and three things I could only have learned by putting circuits on real hardware. The package they were sitting in was already verified by n8n. Every unit test passed. Statement coverage was 98.55 percent. `npm audit` was clean. None of that had anything useful to say about any of the six.

What did have something to say was 121 seconds of QPU time across two IBM machines. This is what it found.

## The gate that lies about itself

The circuit that produced that error contained an Identity gate. So I checked whether `id` was native on that backend.

```
basis_gates ibm_kingston: ["cz","id","rx","rz","rzz","sx","x"]

```

It is right there. IBM's own backend, reporting `id` among its native gates, on the same device that had just refused the job. That made it worse, not better. A user building an ISA circuit sees that list, includes `id` because the vendor says the chip runs it, and the job dies naming an instruction that appears nowhere in their program.

The cause is in the language, not the hardware. `stdgates.inc`, the OpenQASM 3 standard library, defines identity as `gate id a { U(0, 0, 0) a; }`. IBM's parser expands it into the builtin `U`. The target refuses `U`. The name matches a native instruction, and the path never reaches it.

A theory that sounds right is the most expensive kind of wrong, so I put it on hardware. Three control jobs, one variable at a time:

| circuit                                 | result                       |
| --------------------------------------- | ---------------------------- |
| reset + x + rz + cz + barrier + measure | completed, {"01":120,"00":8} |
| rx(pi) alone                            | completed, {"1":123,"0":5}   |
| id + x + measure                        | failed, instruction u        |

Six seconds of quota to turn a theory into a fact.

The fix keeps Identity in the palette and still validates its operands, so a wrong qubit index is still an error rather than a silent drop, but it emits nothing at all. Identity is the no op, so what comes out is mathematically identical and it runs. Same circuit that had failed:

```
QASM emitted:  qubit[2] q; bit[2] c; x q[0];
               c[0] = measure q[0]; c[1] = measure q[1];
status:        completed
counts:        {"01": 249, "00": 7}

```

Reproduced on `ibm_kingston` and on `ibm_marrakesh`.

If you take one thing from this post, take this. `basis_gates` tells you what the chip can execute. It does not tell you what the parser will hand the chip. A gate the vendor lists as native can still be unreachable, because of how the standard library of the language happens to define it, and nothing in your local test suite will ever tell you.

## A gate I built, tested and then deleted

Look at that basis gate list again. `rzz` is in it too.

So I implemented it properly: arity, rendering, palette entry, unit tests, build, redeploy into n8n. Then onto real hardware, at two different angles so a bad parameter could not be the explanation.

```
RZZ(pi):   failed  "Error parsing OpenQASM program"
RZZ(pi/2): failed  "Error parsing OpenQASM program"

```

Parse error, not target error. IBM's OpenQASM parser does not recognise the symbol at all. It never gets far enough to ask the hardware.

At that point I had a suspicion and no proof, which is the same position I had been in twenty minutes earlier with `id`, so I did the same thing. Same circuit, `rzz` removed, nothing else touched.

![n8n Get Results output showing counts 00 at 480 and 01 at 32 over 512 shots on ibm_kingston](https://tuguidragos.com/content/images/2026/08/same-circuit-without-rzz--on-ibm_kingston-1.png)

The control, read back through the node. Job `d9nl060qs0bc73e3ifvg`, the same ID tagged `qa-rzz-control` in the console at the top of this post.

```
status: completed
counts: {"00":480,"01":32}   ->  93.8% "00"

```

Which is exactly what the circuit predicts, since two Hadamards cancel. The program was fine. Only `rzz` broke the parser.

The console screenshot at the top of this post holds all three of those jobs in one frame, consecutive rows on `ibm_kingston`: `qa-rzz-pi` failed, `qa-rzz-half` failed, and directly beneath them `qa-rzz-control` completed.

So I deleted the implementation. All of it, after building it. Deleting working code you have just finished feels like waste.

It was not waste. Shipping it would have recreated the precise trap the `id` fix had just closed: a gate sitting in the palette, listed as native by the backend, failing every job it ever touched. The only difference is that this time I would have put it there myself. The knowledge stayed, written into the README and the CHANGELOG. The code went.

## The third thing only hardware could tell me

The first GHZ-40 run, forty qubits prepared so that they all read 0 or all read 1 together, failed on a restriction that is easy to trip and easy to miss:

```
Gate twirling does not support fractional gates. -- If the PEC, PEA, or gate
twirling option is selected, then make sure to remove all fractional gates
from the circuits.

```

The circuits Qiskit transpiled for a Heron processor in this campaign use parametrised `rx`, which IBM classifies as fractional. Which means anybody who transpiles with fractional gates enabled and ticks Gate Twirling because more error suppression sounds better, loses the job. Dynamical Decoupling and Measurement Twirling carry no such restriction.

That warning now lives in the parameter description itself, where a user reads it inside n8n at the moment it matters, rather than in a document nobody opens.

Not one of those three things was reachable from my laptop: a defect in my own code, a gate I deleted after building it, and a restriction inside IBM's stack. That is the honest case for spending real quota on your own tooling.

The next one is the reverse. Hardware confirmed it. Hardware could never have caused it.

## A measure that wrote outside its own register

This defect exists only because the node can be called without the editor, by an AI Agent for one.

A `measure` gate with no value in the Classical Bit field passed validation and produced a program IBM rejects. Two code paths used different fallbacks for the same missing value. Validation checked `clbit ?? 0`. Rendering used `clbit ?? targets[0]`. Reproduced against the compiled `dist` before the fix:

```
validateGateInput -> VALID (no error)
QASM emitted:
  qubit[3] q;
  bit[1] c;
  c[2] = measure q[2];     <- writes to bit 2 of a one bit register

```

That field can only go missing when the gate object is built outside the n8n editor. By a model calling the node as a tool, by an imported workflow, or through the public n8n API. Inside the editor it always carries a value, so no amount of clicking would ever have surfaced it.

The fix normalises to 0 in `mapGate` and uses the same fallback in the renderer, so the two cannot drift apart again. Confirmed on hardware: the test emitted `c[0] = measure q[2];` and the job completed.

The general form is worth stating plainly. If your node sets `usableAsTool`, every optional field becomes a field a model can omit. Defaults that live in the interface are not defaults.

## Physics does not care what you believe

Every job ran through a local n8n 2.32.7 instance with the node installed exactly the way n8n installs a community package: `npm pack`, extract the real tarball into `.n8n/nodes/node_modules`, `npm install --legacy-peer-deps`. Not `npm link`. If the test does not use the install path real users get, it is not a test of the thing they receive.

The reason quantum circuits make an unusually good test suite is that the answer is known in advance and the machine has no interest in agreeing with you. If any link in the chain is wrong, from building the PUB, the bundle of circuit, parameters and shots a job carries, to decoding hex samples back into counts, the numbers simply do not arrive.

| test                                           | predicted  | measured               |
| ---------------------------------------------- | ---------- | ---------------------- |
| Estimator ⟨Z⟩ on \|1⟩                          | \-1        | \-1.0024               |
| Estimator, Pauli array \["ZI","IZ","ZZ"\]      | +1, -1, -1 | +1.003, -1.014, -1.025 |
| Estimator, coefficient map {"ZI":1.0,"IZ":0.5} | +0.5       | +0.472                 |
| Parametrised rx(theta) at θ = π                | \|1⟩       | {"1":125,"0":3}        |

The parameter sweep is the strongest single piece of evidence in the whole campaign. One submission, five bindings, and a cosine came back out of a superconducting chip:

```
theta      predicted cos(t)    measured <Z>    delta
0.0000          1.0000            1.0013      0.0013
0.7854          0.7071            0.7262      0.0190
1.5708          0.0000            0.0135      0.0135
2.3562         -0.7071           -0.6946      0.0125
3.1416         -1.0000           -1.0058      0.0058

```

Maximum deviation 0.019\. You cannot fake that curve with a broken parser.

One detail in those two tables deserves a word, because a physicist will spot it immediately. Several of the measured [expectation values](https://tuguidragos.com/measurement-is-not-magic-the-born-rule-by-hand/) sit outside the range a Pauli operator can actually take, -1.0058 and +1.003 among them, and no real ⟨Z⟩ ever leaves the interval from -1 to 1\. That is not a parsing fault and it is not the chip misbehaving. The Estimator applies error mitigation by default, and a mitigated estimate is corrected on average rather than clamped to the physical range, so individual points overshoot in both directions. The overshoot is small, it is symmetric, and it is what a working mitigation stack looks like. A parser inventing numbers would not land this close on both sides of the line.

Two parsing details came out of the same campaign, and both were silent failures waiting to happen.

**`num_bits` was the last open question, and it got answered on real data.** The samples arrive as `0x1` and `0x0`. If the API had not sent `num_bits`, my width inference would have returned 1, and the results would have read `{"1":250,"0":6}` instead of `{"01":250,"00":6}`. The second bit would have disappeared without a trace and every count would still have summed correctly. It is present, at 2 and at 64.

**BigInt earns its place at 64 bits.** The wide register test used 2⁶³ + 1\. As an IEEE double that rounds to 2⁶³ and the low bit vanishes, so `parseInt` would have produced `1000...0000`. The parser produced `1000...0001`.

I also built a Bell state out of native gates with no transpiler anywhere, using the two identities that do most of the work: H equals rz(π/2) then rx(π/2) then rz(π/2), and CNOT from control to target equals H on the target, cz, H on the target again. Thirteen gate entries, on `ibm_marrakesh`, 2048 shots:

| outcome | count | share |
| ------- | ----- | ----- |
| 00      | 1046  | 51.1% |
| 11      | 946   | 46.2% |
| 01      | 25    | 1.2%  |
| 10      | 31    | 1.5%  |

97.3 percent correlated, 2.7 percent readout noise, 3 seconds of quota. If you want to see the matrices behind gates like H and CNOT, I worked them by hand in [an earlier post](https://tuguidragos.com/quantum-gates-are-just-matrices-you-can-run-by-hand/).

## Eighty qubits, depth 241, and samples too wide for a double

My README had been recommending Qiskit for transpilation, and that recipe had never been verified end to end. So I ran it. Qiskit 2.2.3 in an isolated environment, and the real topology of `ibm_kingston` read through the node itself with Backend then Get Configuration, which returned 352 coupled pairs and the native gate list. Nothing assumed.

| circuit | logical depth | transpiled depth | CZ gates | shots  | result                          | cost |     |
| ------- | ------------- | ---------------- | -------- | ------ | ------------------------------- | ---- | --- |
| GHZ-12  | 13            | 37               | 11       | 8,192  | 37.7% \|0¹²⟩, 34.3%             | 1¹²⟩ | 4 s |
| GHZ-40  | 41            | 121              | 39       | 15,000 | ranks 1 and 2 of 4,853 outcomes | 6 s  |     |
| GHZ-80  | 81            | 241              | 79       | 25,000 | ranks 1 and 2 of 23,294         | 9 s  |     |
| GHZ-80  | 81            | 241              | 79       | 45,000 | ranks 1 and 2 of 41,172         | 14 s |     |

The heaviest run, in full:

```
80 physical qubits, depth 241, 79 CZ gates, 45,000 shots
|0^80> : 0.48%  rank #1
|1^80> : 0.40%  rank #2
outcome space: 2^80 = 1.2 x 10^24 possible strings
every string exactly 80 bits : PASS
sum of counts = shots (45000) : PASS
payload: 1041 KB downloaded and parsed inside the 30 s timeout

```

Out of 1.2 x 10^24 possible bitstrings, the two GHZ extremes come first and second. On a noisy processor, at depth 241, through 79 entangling gates. The outcome space is far wider than a double can hold exactly.

![n8n executions list showing 75 production executions with a zero percent failure rate and named QA workflows](https://tuguidragos.com/content/images/2026/08/executions.png)

The n8n side of the campaign. Each workflow is one test, named for what it checks, including the 45,000 shot GHZ-80 run at the bottom of the visible list.

All 24 operations went against live infrastructure, not only the interesting ones. Both polling triggers fired with the failure reason attached. Seven error paths. Sessions created, queried, closed, including one batch that genuinely carried two jobs rather than being opened and closed empty. Private jobs, where IBM redacts the submitted parameters and leaves the tags visible, which confirms the redaction is selective exactly as documented.

And one test I did not plan. Partway through, `ibm_marrakesh` went into maintenance, so I checked on the spot whether Get Least Busy would exclude it:

```
marrakesh state: message "maintenance"
Get Least Busy candidates: kingston (queue 2), fez (queue 5)
marrakesh excluded: PASS

```

`ibm_fez` is the only backend I touched without running anything on it. It was queried through the API and never received a job.

## The filter that returned everything and never said so

The remaining defects are a different species. They were not failures at all. They were wrong answers, delivered confidently, with a 200 on them.

Filtering jobs by tag did not filter. It did not error. It returned everything.

n8n serialises an array of query parameters as `tags[]=a&tags[]=b`. IBM's API recognises repeated keys, `tags=a&tags=b`, and silently ignores what it does not recognise. No warning. Status 200, full list, every time.

```
BEFORE arrayFormat:
  filter 'qa-audit'             -> 20 jobs, first ones tagged "qa-ghz80-max"
  filter with a nonexistent tag -> 20 jobs

AFTER arrayFormat: 'repeat':
  filter 'qa-audit'             ->  1 job,  tags ["qa-audit","retagged"]
  filter 'qa-audit, retagged'   ->  1 job   (real AND)
  filter with a nonexistent tag ->  0 jobs

```

The unit tests passed the whole time, because they asserted the shape of the request my code built. Nobody had ever asked the server what it did with it. This is the cleanest example I have of the distance between "the tests pass" and "it works", and it only closed because I checked a filter against the live API instead of against my own expectations.

Three smaller ones came from the same family of misplaced trust. `parseResults` guarded with `?? []`, which catches only `null` and `undefined`, so a `results` field that was not an array reached `.map` and threw a bare `TypeError` instead of a readable n8n error. It was found by writing a test that failed, not by reading the code. The numeric fields trusted the interface, because `minValue` in n8n is a visual hint and an expression can deliver a string, a float or a negative straight into the request, so `shots` went into the PUB unclamped and wasted a submission. And Submit checked less than Import did: the literal string `this is not qasm` was accepted, received a job ID, queued, and failed on IBM's servers. That cost 2 seconds of quota to learn.

## Coverage measures what ran, not what was right

The suite went from 140 tests to 185\. Statements from 98.55 to 99.8 percent, branches from 89.81 to 97.83, lines to 100\. Thresholds were raised from 85/85/80 to a set that sits directly under the measured figures, so a regression now trips CI instead of passing quietly. Ten branches remain uncovered and each is commented where it lives, because each is unreachable by construction.

Here is the part that changed how I read a coverage report. **The `measure` bug was on a line reported as 100 percent covered.** The existing test passed `clbit` explicitly, so the line executed every run and the fallback branch never did. Same story with `parseResults`.

Coverage tells you which lines ran. It has no opinion whatsoever about whether they were correct.

## A failed circuit is not free

Worth knowing if you are on the Open plan and its 600 seconds per rolling 28 day window.

IBM defines usage as the time a QPU is locked for your workload, and its documentation is explicit about failures: a job that fails from a system error reports zero usage, but a job that fails through user error, or is cancelled by the user, is charged for whatever was consumed up to that point, **including the overhead of preparing the QPU to run it**. The same page puts that per sub-job overhead at approximately 2 seconds.

That is exactly what I measured. Every one of my five deliberate negative tests, the invalid QASM, the `id` gate, both `rzz` attempts and GHZ-40 with Gate Twirling, cost precisely 2 seconds. Ten seconds of that 600 spent on circuits designed to fail. That is a price worth knowing before you plan a campaign.

The same page defines batch usage as the cumulative QPU lock time of all jobs in the batch, which means the Batch rows in the console are aggregates of jobs already listed individually. Adding them to a per job total double counts.

## What 0.3.3 ships, and what it took to publish it

![GitHub repository page for the n8n-nodes-ibm-quantum community node at release 0.3.3](https://tuguidragos.com/content/images/2026/08/n8n-nodes-ibm-quantum.png)

The repository at commit 3516e51\. Three nodes, one credential, twenty four operations, zero runtime dependencies.

[n8n-nodes-ibm-quantum](https://www.npmjs.com/package/n8n-nodes-ibm-quantum) is three nodes and one credential, MIT, zero runtime dependencies. The [source is on GitHub](https://github.com/TuguiDragos/n8n-nodes-ibm-quantum). Circuits travel as OpenQASM 3 strings and the IBM Cloud API key is exchanged for a short lived IAM bearer token at request time. Twenty four operations across Backend, Circuit, Job, Session and Account.

Four things are new, each verified against the live API rather than a mock:

- **A Program filter on Job List.** Sampler or Estimator. Checked live: 20 sampler, 12 estimator, empty returns both.
- **Multiple Tags filters** on Job List and both triggers, up to the eight the API accepts, with AND semantics. A tag that does not exist now returns zero jobs, which is what the old code could not do.
- **An `unparsedSamples` field** that appears only when the parser cannot read part of a register, so a gap between `counts` and `shots` is visible instead of silent. Absent on healthy data, confirmed present on the 80 qubit payload.
- **A documented recipe for ISA circuits without a transpiler**, the one that produced the Bell state above.

Then there is the part that has nothing to do with quantum computing. I ran the official `@n8n/scan-community-package` against my own published package, the one already carrying the verified badge.

```
BEFORE (git HEAD = published 0.2.3): passed=false  errors=10
AFTER  (repaired working tree):      passed=true   errors=0

```

Ten errors, on a package that was verified and installed by other people. The scanner does not lint your working tree. It checks the provenance attestation, downloads the source from the commit that attestation points to, and lints it with `eslint-plugin-n8n-nodes-base` in addition to the community nodes plugin. My local config loaded only the second, and did not lint `package.json` at all.

One of the ten is worth showing in full, because it is the kind of rule you cannot guess at. Both trigger nodes failed the display name check, which accepts exactly one trailing parenthetical, and mine was not the one it accepts.

```js
const displayValue = displayName.value.replace(/\s*\(Beta\)$/, "");
if (!displayValue.endsWith("Trigger")) { /* report */ }

```

`(Beta)` is stripped before the check. `(Unofficial)` is not. If you maintain an n8n community node, run `npm run scan` against your published package, not your working tree.

The rest of the release, briefly:

- **Node 20 is out.** It reached end of life on 30 April 2026, so `engines.node` moved to `>=22` and CI runs on 22 and 24\. To be accurate: this is a policy decision, not a technical necessity. The n8n 1.x line is still actively published and still permits Node 20.19\. I dropped it because shipping against an unpatched runtime is a bad default.
- **Publishing moved to npm trusted publishing over OIDC.** The token had expired, and instead of regenerating it I removed it. The workflow now mints a short lived, workflow scoped credential, provenance attestations generate automatically, and there is nothing left in the repository to rotate. One trap on the way: trusted publishing needs npm 11.5.1 or newer, and Node 22 ships npm 10.9.8, so the publish job moved to Node 24.
- **The lint config now matches the scanner**, including `package.json`, which needs the TypeScript parser because those rules walk a TSESTree AST. Roughly a dozen rules had never run locally. I verified it by reintroducing each class of error and confirming the lint failed.
- **Dependencies aligned to the versions that actually matter:** `@n8n/eslint-plugin-community-nodes` 0.27.0, the version the scanner itself pins, and `n8n-workflow` 2.32.1, the exact version inside n8n 2.32.7\. All four `npm audit` findings cleared. TypeScript 7 stays out, because it drops `moduleResolution=node10` and typescript-eslint does not load against it.
- **CI caught something I could not have caught locally.** The lockfile, generated on macOS with npm 10.9.8, omitted optional binaries for other platforms. npm 11 on Node 24 is stricter and refuses `npm ci`. Regenerated with npm 11, 463 entries added, verified npm 10 still accepts it.

Three commits, 26 files, 1922 insertions, 2229 deletions. The third one exists because on rereading I noticed the CHANGELOG claimed the new thresholds meant a regression would trip the gate, and it would not have, since CI ran `npm test`, which does not check thresholds. I made the sentence true rather than deleting it.

```
main       3516e51
npm        0.3.3 latest, published 2026-08-02T15:13:46Z
gitHead    ae4a461  (matches the git tag exactly)
engines    >=22
runtime dependencies: zero
provenance npm attestation + SLSA, generated automatically through OIDC
package    38 files, 170.7 KB unpacked

```

The package downloaded from npm, not my local build, also passed all 22 checks of the n8n loader contract.

## What I am not claiming

**That the node has no bugs.** This session is the counterexample. It was verified, tested and covered, and it had six. It has now been interrogated seriously. That is a different sentence from "it is correct".

**That coverage is meaningless.** Two defects sat on fully covered lines, which makes coverage a floor rather than a verdict. It is still worth having.

**That `sx` is broken.** I did not test it individually on hardware. What I know is that the palette has no way to emit it without going through the builtin `U`, so it is not offered. That is not the same as "tested and it fails".

**That every gate classification is empirical.** The gates marked "transpile first" in the README are classified from the `basis_gates` the backend reports, which is a solid source, but only `x`, `rx`, `rz`, `cz`, `reset`, `barrier` and `measure` have been confirmed by jobs that completed.

**That Node 20 could not run this.** It could. I dropped it on policy.

## Questions people ask

### Why does my IBM Quantum job fail with "the instruction u is not supported" when my circuit has no u gate?

Almost certainly because it contains an identity gate. `stdgates.inc` defines `id` as `U(0, 0, 0)`, IBM's parser expands it into the builtin `U`, and the target refuses `U`. The backend lists `id` in its own `basis_gates`, which is what makes this so confusing. Remove the identity gates. They are no ops, so the circuit is unchanged.

### What does reason\_code 1517 mean?

The circuit was not transpiled to the target's native gate set. Either transpile it with Qiskit against the real backend, or build it directly from the native gates the device reports.

### Why does Gate Twirling fail my transpiled circuit?

Because Qiskit, with fractional gates enabled, transpiles for Heron processors using parametrised `rx`, which IBM classifies as a fractional gate, and gate twirling does not support fractional gates. Turn it off. Dynamical Decoupling and Measurement Twirling have no such restriction.

### Can I use rzz on IBM hardware through OpenQASM 3?

Not through the REST API as of August 2026\. The backend lists `rzz` in `basis_gates`, but submitting it produces `Error parsing OpenQASM program` before it ever reaches the target. Verified twice on `ibm_kingston`, with a control circuit confirming the rest of the program was valid.

### Do failed quantum jobs use up my monthly quota?

Yes, when the failure is your fault. IBM reports zero usage for a system error, but a user error or a manual cancellation is charged for whatever was consumed, including the roughly 2 second QPU preparation overhead. Five deliberately broken circuits cost me 10 seconds.

### Can you build an ISA circuit without Qiskit?

For small circuits, yes. Through this node's palette the usable native set on a Heron processor is `x`, `rx`, `rz`, `cz`, plus measure, reset and barrier. H equals rz(π/2), rx(π/2), rz(π/2), and CNOT equals H on the target, cz, H on the target. A Bell state built that way returned 97.3 percent correlation on `ibm_marrakesh`.

### Why did a verified n8n community node fail the official scan?

Because the scanner downloads the source from the commit the provenance attests to and lints it with `eslint-plugin-n8n-nodes-base`, which many local configs do not load, and it lints `package.json`, which many do not cover. Run `npm run scan` against the published package.

## The run in numbers

Run window: 2 August 2026, 13:38:45 to 14:22:19 UTC. Forty three minutes.

|                                                   |                 |
| ------------------------------------------------- | --------------- |
| jobs submitted                                    | 28              |
| completed                                         | 22              |
| failed, of which 5 were deliberate negative tests | 6               |
| QPU time consumed                                 | 121 s           |
| jobs on ibm\_kingston                             | 25              |
| jobs on ibm\_marrakesh                            | 3               |
| jobs on ibm\_fez                                  | 0, queried only |
| monthly Open plan allowance                       | 600 s           |

The per job usage column sums to exactly 121, and that matches the change in reported instance usage across the campaign. Two independent sources, same number.

The jobs behind the claims in this post, so you can match them against the console:

| tag             | job ID               | backend        | what it shows                                 |
| --------------- | -------------------- | -------------- | --------------------------------------------- |
| qa-idfix        | d9nkqacsfqic73ar5o0g | ibm\_kingston  | the identity circuit completing after the fix |
| qa-rzz-pi       | d9nkvm4sfqic73ar5t5g | ibm\_kingston  | rzz at π, parse error                         |
| qa-rzz-half     | d9nkvmcsfqic73ar5t60 | ibm\_kingston  | rzz at π/2, parse error                       |
| qa-rzz-control  | d9nl060qs0bc73e3ifvg | ibm\_kingston  | same circuit without rzz, completed           |
| qa-bell-native  | d9nktfoqs0bc73e3id5g | ibm\_marrakesh | Bell state from native gates only             |
| qa-est-map      | d9nkmbs60llc73ca7e90 | ibm\_kingston  | Estimator with a coefficient map              |
| qa-param        | d9nkmkc60llc73ca7epg | ibm\_kingston  | parametrised rx at θ = π                      |
| qa-bigpayload   | d9nkn7oqs0bc73e3i53g | ibm\_kingston  | 64 bit register, BigInt decoding              |
| qa-ghz12-qiskit | d9nl2tk60llc73ca7v1g | ibm\_kingston  | first Qiskit transpiled run                   |
| qa-ghz40        | d9nl3rssfqic73ar622g | ibm\_kingston  | Gate Twirling on fractional gates, failed     |
| qa-ghz40        | d9nl450qs0bc73e3ikm0 | ibm\_kingston  | same circuit, twirling off, completed         |
| qa-ghz80-max    | d9nl56ssfqic73ar63fg | ibm\_kingston  | 80 qubits, depth 241, 45,000 shots            |

The environment, if you want to reproduce any of it: n8n 2.32.7 on Node 22.23.1, with an isolated data folder outside `~/.n8n` and telemetry disabled. Qiskit 2.2.3 with NumPy 2.0.2 in a separate virtual environment, used only for transpilation. IBM Quantum Platform in us-east, `IBM-API-Version` 2026-04-15, Open plan, Heron r2 processors at 156 qubits, which report a max\_shots of 100,000 in their configuration, a legacy field IBM says it no longer enforces.

> **A note on one number.** The published CHANGELOG for 0.3.3 records 118 seconds of QPU time. That figure was written before the campaign finished. The number in this post is 121, and it is the one supported by both the per job usage column and the reported instance usage. I have left the CHANGELOG as published rather than editing history, so this note is here to explain the difference rather than hide it.

## Where to find it

The node is on npm as [n8n-nodes-ibm-quantum](https://www.npmjs.com/package/n8n-nodes-ibm-quantum). It installs from the [community nodes screen](https://docs.n8n.io/integrations/community-nodes/installation-and-management) on self hosted n8n, and directly from the canvas on n8n Cloud because it is verified. Source, CHANGELOG and the full gate table are in [the repository](https://github.com/TuguiDragos/n8n-nodes-ibm-quantum). It is unofficial and not affiliated with IBM.

Earlier chapters, if you want them: [the launch and what the three nodes do](https://tuguidragos.com/ibm-quantum-node-for-n8n/), and [the first end to end Bell state on real hardware](https://tuguidragos.com/quantum-circuits-ibm-hardware-n8n/), which covers the transpilation step most first attempts miss. IBM's documentation on [workload usage](https://quantum.cloud.ibm.com/docs/en/guides/estimate-job-run-time) is the source for the quota accounting above, and worth reading before you spend a monthly allowance.

What I keep turning over is that none of the six defects came from not knowing enough quantum computing. Every one came from trusting a layer. That green tests meant working behaviour. That a covered line meant a correct line. That a gate the vendor lists as native is a gate you can use. The hardware had no opinion about any of it. That is the whole value of running the thing for real.