Skip to content
Home/Blog/Common Cirq Errors and How to Fix Them
CirqBeginnersBest Practices

Common Cirq Errors and How to Fix Them

The mistakes that trip up Cirq users most: mixing qubit types that look equal but aren't, duplicate measurement keys, unexpected moment packing, and unresolved parameters. Each with the fix.

FreeQuantumComputing
·· 6 min read

Cirq's errors tend to come from its data model rather than from API churn. Qubits, moments, and measurement keys behave in specific ways that aren't obvious from the method names, and most confusion traces back to one of a handful of recurring mismatches.

Mixing LineQubit and GridQubit

import cirq

q1 = cirq.LineQubit(0)
q2 = cirq.GridQubit(0, 0)
q1 == q2  # False, always

LineQubit(0) and GridQubit(0, 0) are never equal, even though a beginner might mean them as "the same qubit 0." Cirq qubit equality checks type and coordinates together, not index alone. Mixing qubit types across a circuit, one function returning LineQubits and another expecting GridQubits, silently creates a circuit with more distinct qubits than you intended rather than raising an error. Pick one qubit type per circuit and stick to it, and if you're combining code from two sources, check what qubit type each one produces before appending gates.

Duplicate measurement keys errors

for i in range(3):
    circuit.append(cirq.measure(qubits[i], key='m'))  # same key every loop

Cirq requires every measurement in a circuit to have a unique key so results are looked up afterward without ambiguity. Reusing the same key string across a loop, easy to do when a placeholder key gets left in, raises an error the moment the circuit tries to build or simulate. Key each measurement uniquely:

for i in range(3):
    circuit.append(cirq.measure(qubits[i], key=f'm{i}'))

Gates packing closer together than expected

circuit.append() defaults to InsertStrategy.EARLIEST_OR_NEW, which slots each new operation into the earliest moment where it doesn't conflict with an existing operation on the same qubit, rather than always starting a new moment. If you're assuming one append() call means one moment, and your circuit's depth or hardware-timing assumptions depend on that, the packed layout produces different results than you expect, without an error to flag it. Pass an explicit strategy when moment boundaries matter:

circuit.append(ops, strategy=cirq.InsertStrategy.NEW_THEN_INLINE)

or build cirq.Moment objects directly when you need exact control over what runs in parallel.

TypeError: Gate was not a cirq.Gate

This shows up when something that isn't a proper cirq.Gate subclass gets applied to qubits with .on(), commonly a custom gate class missing required methods (_num_qubits_, _unitary_ or _decompose_), or a raw numpy array passed where a gate object was expected. Cirq's gate protocol is duck-typed but strict about which methods it checks for. If you're defining a custom gate, subclass cirq.Gate and implement at minimum _num_qubits_ plus either _unitary_ or _decompose_, rather than trying to construct a gate-like object ad hoc.

Unresolved parameters at simulation time

import sympy
theta = sympy.Symbol('theta')
circuit = cirq.Circuit(cirq.rx(theta).on(q))
cirq.Simulator().simulate(circuit)  # fails: unresolved symbol

A parameterized circuit built with sympy symbols needs its parameters resolved to numeric values before a simulator runs it. Forgetting the resolution step, easy to do when moving from building a variational circuit to evaluating it, raises an error about an unbound symbol rather than a silently wrong result:

resolved = cirq.resolve_parameters(circuit, {theta: 0.5})
cirq.Simulator().simulate(resolved)

or pass a cirq.ParamResolver directly to simulate()'s param_resolver argument instead of resolving the circuit ahead of time.

The pattern behind most of these

Cirq's errors mostly come from its explicitness: qubit identity, moment structure, and parameter binding are all things Cirq makes you handle directly rather than inferring for you. That's a deliberate design choice, closer to the underlying hardware model than a higher-level abstraction, and most of what trips people up is code written with a looser mental model than Cirq enforces.