open-standards/wai/wai-quantum/docs/qasm-diagnostics.md
Transaction Science d1c6860248 wai-quantum: a job binds its parameters, and the reader carries each gate's derivative by them
A job's "params" gives each of its program's parameters (input float,
input angle) its value, bound exactly before the program is read; a
parameter left without one is refused (Q114, J040), and a sweep may fix
some parameters in "params" while it sweeps the others. qasm::tangents
reads a program with every gate's derivative by each parameter, carried
forward through arithmetic, the built-in functions, gate definitions,
broadcast and loops; what it cannot follow is refused on its line (Q129).
The job codes for gradients, optimisation and the builders (J041 to J043)
join the table.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-31 09:48:42 -04:00

19 KiB

OpenQASM reader: diagnostic codes

Every refusal and warning the reader gives (wai_quantum::qasm), and every construct it lowers, carries or keeps verbatim, has a code. A refusal or a warning reads, on every surface:

line 3: unknown gate foo [Q103]

and, as data (wai-quantum lint --json, the MCP servers' lint_qasm, the job service, the Studio), carries its code, its outcome, its message and where it stands: line, column and length, in characters.

Stability. A code never changes meaning once released. A construct that comes to be supported gets a new code for what now happens to it; the old code keeps its row, marked retired, so a code in an old log or receipt still means what it meant then. New codes are only ever added.

Outcomes.

  • refused: the program is not read, and nothing runs.
  • lowered: read and lowered exactly to the engine's gates and steps.
  • carried: kept in the program as written (its timing, its outputs), changing nothing a method computes unless the method says it uses it.
  • preserved: kept verbatim for export, never executed.
  • warned: read, with something the person should know; the job's result lists it under diagnostics.

What is asked of a program (the request, the method, an intent, a repair, the host) has codes of its own, J…: job-refusals.md. The verdict (verdicts.md) carries a refusal's codes, and the repair (wai-quantum repair, repair_qasm) makes the fixes that are mechanical on the lines a diagnostic flags.

The table is also served as data: wai_quantum::qasm::diag::codes() in Rust, wai-quantum diagnostics [--json] on the command line, the qasm_diagnostics tool of both MCP servers, and engine_diagnostic_codes() in the browser engine. A test holds this page to the code's table.

Code Outcome Meaning
Q001 refused A character that is not part of the language.
Q002 refused A number that does not read: a malformed literal, or one too large to hold.
Q003 refused A string, a block comment, a bracket or a calibration block that is not closed.
Q004 refused Something else was expected here: a ;, a name, an expression or a statement (the message says which).
Q005 refused A statement in a place the language does not allow it: else with no if, case outside switch, a declaration inside a gate.
Q010 warned An OPENQASM version other than 2.x or 3.x: the program is read as OpenQASM 3.
Q011 warned An include of a file other than the standard libraries (stdgates.inc, qelib1.inc): its definitions are not read, so a gate it defines is unknown.
Q012 lowered include "stdgates.inc" or "qelib1.inc": the standard gates, U, gphase and OpenQASM 2's names are built in.
Q013 warned A pragma or annotation the reader does not act on: kept, not applied.
Q100 refused The program declares no qubits.
Q101 refused A name declared twice in one scope, or given to two kinds of thing (a register and an integer).
Q102 refused A name that is not declared: a register, a variable, an alias or a subroutine.
Q103 refused A gate that is neither in the standard library nor defined in the program.
Q104 refused A gate or subroutine given the wrong number of parameters, qubits or arguments.
Q105 refused A declaration only the top level may make (qubits, a gate, a subroutine, an extern) inside a block.
Q106 refused A word of the language, or a built-in constant (pi, tau, euler), used as a name.
Q107 refused An index or slice outside its register or array.
Q108 refused Registers of different lengths in one statement that applies to whole registers.
Q109 refused One qubit named twice in one gate.
Q110 refused A value of the wrong type here: a float where an integer is needed, a complex gate parameter, a qubit where a value is needed.
Q111 refused More qubits than the reader takes (65 536).
Q112 refused An integer outside its type's range (a negative uint, a value too wide for int[n]), or integer arithmetic that overflows.
Q113 refused Division, or a remainder, by zero.
Q114 refused An input given no value, or a value given for an input the program does not declare.
Q115 refused An input of a type the reader takes no value for: only int and uint inputs are given values.
Q116 refused A value that depends on a measurement used where the reader needs it on reading: a gate parameter, an index, a size, a loop's range.
Q117 refused A gate parameter that is not a finite number.
Q118 refused Integers divided with a remainder where a real number is wanted: OpenQASM 3 truncates 1/2 to 0 and OpenQASM 2 reads it as 0.5, so write 1.0/2.
Q119 refused ^ between integers in a program that does not say OPENQASM 3: OpenQASM 3 reads it as exclusive or, OpenQASM 2 as a power; write ** for a power.
Q120 warned ^ between real numbers, read as a power as OpenQASM 2 reads it; OpenQASM 3 writes **.
Q121 warned A value rounded to its declared width, as the language defines (angle[n] to n bits of a turn, float[32] and float[16] to single and half precision); the message gives the amount.
Q122 refused A type width the reader does not hold: a float other than float[16], float[32] and float[64], an integer or an angle wider than 64 bits.
Q123 refused A cast the language does not allow, or one whose value does not fit.
Q124 refused Physical qubits ($0) in a program that also declares qubits.
Q125 refused A call of an extern function, whose body is outside the program.
Q126 refused A call of an opaque gate, or of a gate with only a calibration: its matrix is not known.
Q127 refused An assignment to a constant, an input or a loop variable.
Q128 refused A measurement where a value is needed that is not a bit (measurement gives bits, into a bit register).
Q129 refused A parameter (input float, input angle) a gradient cannot follow to the gates: under a modifier, in a classical variable, a condition, an index, a size, a loop's range, a subroutine or gphase, or one whose type rounds it (angle[n], float[32]); a gradient follows a parameter through arithmetic, the built-in functions and gate definitions into a gate's arguments.
Q200 lowered A gate the program defines, inlined at each call with its parameters bound.
Q201 lowered ctrl @ and negctrl @ on any gate, lowered exactly to standard gates (a negative control is a control between two x).
Q202 lowered inv @ on any gate, user gates included: each gate's exact inverse, in reverse order.
Q203 lowered pow(k) @ with an integer k: angles scaled, or the gate repeated; a negative k repeats the inverse.
Q204 lowered pow(r) @ with a fractional r where an exact gate exists: the principal power (pow(1/2) @ x is sx, pow(r) @ rz(θ) is rz(rθ) for |θ| < 2π).
Q205 refused pow(r) @ with a fractional r where no exact gate exists here: a user gate, u, cu, or a rotation by 2π or more.
Q206 lowered gphase(θ): a global phase, which no measurement sees, dropped; under controls it is a phase on the controls.
Q207 refused A control modifier that adds no control: ctrl(0) @.
Q208 refused Modifiers that add more controls than the reader lowers (16).
Q209 refused Gate definitions or subroutine calls nested deeper than 32.
Q210 refused A program that expands to more gates than the reader holds (2 000 000).
Q211 refused A modifier on something that is not a gate.
Q212 refused A statement a gate's body may not hold: a gate holds gate calls, gphase, barrier, loops and conditions known on reading.
Q300 lowered An if, while or switch whose condition is known on reading: decided then.
Q301 lowered A condition on measured bits (c[0], c == 3, c >= 2, &&, ||, !), compiled to steps that branch on them.
Q302 refused A condition that reads neither measured bits nor values known on reading.
Q303 refused A bit register of more than one bit used as a condition: compare it with a number, as c == 3.
Q304 refused A comparison with a number that does not fit in the bits compared.
Q305 refused A negated operand compared with == or != (!c == 1): write c != 1.
Q306 refused Classical arithmetic on measured bits at run time, beyond a condition, or a comparison between two measured values: the program's steps branch on bits and hold no other run-time values.
Q307 refused A condition that reads more than 64 bits.
Q308 lowered for over a range, a set or an array: unrolled, once per value.
Q309 lowered while whose condition is known on reading: unrolled until it fails.
Q310 refused A while whose condition reads measured bits and that declares no bound: add @wai.max_iterations N before it.
Q311 warned A while on measured bits run at most its declared bound (@wai.max_iterations N): a run that still meets its condition after N iterations stops looping there.
Q312 refused A program that does not finish unrolling within the reader's bound (20 000 000 statements and loop iterations).
Q313 refused A range with a zero step, or that does not read as [start:end] or [start:step:end].
Q314 refused break or continue outside a loop, or return outside a subroutine.
Q315 refused A return with a value under a condition on measured bits.
Q316 lowered break, continue, return and end: under a condition on measured bits, a jump forward in the steps.
Q317 lowered switch: decided on reading, or a chain of conditions on measured bits.
Q318 lowered A def subroutine, inlined at each call: classical arguments by value, qubits by reference, its return value given back.
Q319 refused A bit given anything but a measurement at run time: bits are written by measurement (a declaration may give them 0).
Q320 refused A measurement whose result goes nowhere: measure q; while bit registers are declared (write c = measure q;).
Q321 refused Qubits measured into a different number of bits.
Q322 lowered A bit declared inside a block or a subroutine: a bit of its own, which the steps read and the results do not show.
Q400 warned The method applies no durations: the program's delays, boxes and stretches change nothing it computes, and the result says so.
Q401 carried delay[d] on qubits, carried in the program's timing.
Q402 carried box (with or without a duration), carried in the timing around the gates it holds.
Q403 carried stretch: a duration a scheduler would solve, carried by name.
Q404 carried barrier, carried in the timing; it changes no gate.
Q405 refused durationof(…): it needs gate durations, which the program does not give the reader.
Q406 refused A duration that does not read: no unit, negative, or not known on reading.
Q407 carried A gate's duration (x[20ns] q;), carried in the timing, not applied.
Q450 preserved defcal: kept verbatim for export, never executed; the gate's matrix comes from its gate definition or the standard library.
Q451 preserved cal { … }: kept verbatim for export, never executed.
Q452 preserved defcalgrammar: kept verbatim for export.
Q453 lowered In a pulse run, a cal or defcal body read as OpenPulse and lowered to the schedule on frames (plays, delays, phase and frequency changes, captures and barriers) that the pulse simulator integrates.
Q454 refused In a pulse run, a defcalgrammar other than "openpulse": the pulse reader reads OpenPulse alone.
Q455 refused A statement in a calibration that the pulse reader does not take: classical control, a frame's attributes or get_phase, an extern function, a frame made inside a defcal, a nested calibration, or a defcal over qubit arguments (the message names it and what to write instead).
Q456 refused A waveform that does not read: a template the reader does not know, arguments of the wrong number or kind, a length or a width that is not positive, a sample that is not a number, or more samples than it holds.
Q457 refused A frame or a port that does not read: a play, a delay or a phase or frequency change on a name that is not a frame, newframe on a name that is not a port, a frequency that is not a number, or a port that reaches no qubit.
Q458 refused A duration in a calibration that is not a whole, non-negative number of samples at the sample period (dt), or a schedule longer than the reader holds.
Q459 refused In a pulse run, a gate or a measurement on physical qubits that no defcal calibrates for those qubits and those parameters.
Q460 refused In a pulse run, a statement outside the calibrations that the pulse reader does not take: declared qubits (a pulse program names physical qubits, $0), a modifier, reset, classical control, a subroutine, or a measurement into something other than a bit.
Q461 refused A capture that does not read: not on a frame of an acquisition port, without a duration or a waveform, or its result put somewhere other than a bit.
Q462 warned A play on a measurement port: scheduled and timed, its effect on the readout not simulated (a capture reads the qubit's state).
Q500 refused An angle that is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32): the bit-exact method refuses it, never rounds it; the methods in double precision take it.
Q501 refused More than 255 qubits for the bit-exact circuit.
Q502 refused A program that measures a qubit and then acts on it, resets one after its first gate, or acts on measured bits: the bit-exact circuit takes programs whose measurements all come at the end.
Q600 carried An output declaration, carried into the result: its bits (their places in each outcome) or its value.
Q601 refused An output that is not a bit and whose value depends on a measurement at the end.
Q700 refused A file that does not read in the format named: QIR that is not LLVM text with one entry point, or jeff that is not a Cap'n Proto message of the jeff schema (a pointer outside the message, a struct or list of the wrong shape, more than the reader takes); the message says what and where.
Q701 refused A format version the reader does not take: QIR whose qir_major_version is not 1 or 2, or jeff other than 0.2 and 0.3.
Q702 warned A QIR module that leaves out what its profile requires (the qir_profiles attribute, the version flags, required_num_qubits, required_num_results, the entry_point attribute of its only function): read from what it holds, and said so.
Q703 refused A QIR profile the reader does not take: qir_profiles names neither base_profile nor adaptive_profile.
Q704 refused What the module's own QIR profile forbids: under the base profile a branch, a classical instruction, reading a result, or a gate or reset on a qubit after its measurement; under the adaptive profile an optional capability its module flags do not declare (computation on integers or floats of a type, IR-defined functions, loops, switch, several returns, dynamic qubits or results, arrays).
Q705 refused A QIR capability the module may use that this reader does not take: loops, switch, phi, IR-defined functions, dynamic allocation of qubits or results, arrays, controlled forms that take their controls in an array, or a classical value computed from a measurement anywhere but a branch's condition.
Q706 refused An instruction or function the reader does not know: a quantum intrinsic outside the gates it reads (docs/formats.md lists them), a runtime function it does not take, an LLVM instruction no profile lists, or a function a module declares and does not define.
Q707 refused A QIR operand that does not read: a qubit or result that is not a constant index, an index past required_num_qubits or required_num_results, or an angle that is not a finite number known on reading.
Q708 refused A value whose meaning the program's text cannot keep: in QIR a result read, measured again and only then branched on; in jeff a qubit the two sides of a branch on a measurement leave in different places.
Q709 warned Rotations at angles that are not dyadic multiples of 2π, read at their exact doubles: the double-precision methods take them; the bit-exact method refuses them (Q500).
Q710 refused A jeff custom gate the reader does not know: its name is not a gate of the standard library (in any case), or its qubits or parameters are not that gate's.
Q711 warned A jeff custom gate named as a gate of the standard library (H, CX, Rx, in any case) with that gate's qubits and parameters: read as that gate, by its name alone.
Q712 lowered A jeff Pauli-product rotation, exp(iθP) as its schema defines it, lowered exactly to basis changes, a parity ladder and one rz.
Q713 refused A jeff value used where it cannot be: a qubit or register used twice, a value used before it is defined or never defined, a cycle, or a value of the wrong type or count for its operation.
Q714 refused A jeff value the reader needs on reading and cannot know: a gate angle, a loop's bounds or a while condition from a measurement, a register's size or index, a switch on a value that is neither known nor a measured bit, or integer arithmetic on a measured bit beyond not, and, or, xor, eq and select.
Q715 lowered jeff's structured control flow: a for or while decided on reading unrolled, a switch on a known value decided, a switch on a measured bit written as if … else, and a call of a function the module defines inlined.
Q716 warned A jeff entry point that takes qubits: they are the program's first qubits, starting in |0⟩, and the qubits it returns are not measured.
Q720 refused A program the format written cannot hold as it is: under QIR's base profile a measurement in the middle, a reset after a gate or a condition (write the adaptive profile), a loop in QIR, or in jeff a branch on a measured bit.
Q721 warned What the format read or written has no place for, left out and said so: delays, boxes, barriers and gate durations, calibrations, output declarations, and classical values recorded as output.

See qasm-feature-matrix.md for each construct of OpenQASM 3.1 and its code. The codes from Q700 are those of the readers and writers of other formats (QIR and jeff, formats.md).