Skip to content
← Back to activity

Immutable solution version

Diagnose and fix astropy Quantity and unit errors

Version 2Sign in to save

Complete solution

Shows how to fix diagnose and fix astropy Quantity and unit errors. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

TL;DR

For "UnitConversionError: 'm' (length) and 's' (time) are not convertible": scope the equivalency to the block that needs it rather than enabling it globally: python with u.set\_enabled\_equivalencies(u.dimensionless\_angles()): x = (0.5 u.rad).to(u.dimensionless\_unscaled) # 0.5

UnitConversionError: 'm' (length) and 's' (time) are not convertible

When to use

You are seeing this: Nearly every unit bug is one of four failure modes, and this procedure identifies which one from the exception (or its absence) before you touch the code. Use this skill when you run into "Diagnose and fix astropy Quantity and unit errors".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Use this when arithmetic with astropy.units raises UnitConversionError or TypeError, or when units silently vanish and downstream numbers come out wrong by orders of magnitude. Nearly every unit bug is one of four failure modes, and this procedure identifies which one from the exception (or its absence) before you touch the code.

1. Read the exception class, it names the failure mode

  • UnitConversionError: 'm' (length) and 's' (time) are not convertible the two operands have genuinely incompatible physical types, or they are convertible only through an equivalency you have not enabled (section 2).

  • TypeError: only dimensionless scalar quantities can be converted to Python scalars, you called float(), int(), or round() on a quantity that still carries a physical unit (section 3).

  • No exception, but later code misbehaves and values look like bare numbers , the units were silently dropped, almost always by a numpy function that was not told to preserve subclasses (section 4).

Check the physical types of both sides first, it is the fastest diagnostic:

from astropy import units as u

q = 500 * u.nm
print(q.physical_type)                 # 'length'
print(q.is_equivalent(u.Hz))           # False -- needs an equivalency
print((10 * u.m).is_equivalent(u.km))  # True -- plain conversion, no equivalency needed

2. UnitConversionError: incompatible types vs missing equivalency

UnitConversionError from .to() or from +/- means one of two things. Distinguish them with is_equivalent():

  • is_equivalent(target) is True, the conversion is legal but something else is wrong (usually a plain number was passed where a Quantity was expected). Convert explicitly with .to().

  • is_equivalent(target) is False, either the conversion is genuinely meaningless (length to time: your formula is wrong, fix the math), or it needs an equivalency: a context-dependent mapping between physical types.

The equivalencies you will actually reach for:

freq = (500 * u.nm).to(u.Hz, equivalencies=u.spectral())  # wavelength [-] frequency [-] energy
  • u.spectral(), wavelength, frequency, energy. It does not cover Doppler shifts; that is a separate equivalency, a common confusion.

  • u.doppler_optical(rest_wavelength) / u.doppler_radio(...) wavelength/frequency [-] velocity, optical and radio conventions.

  • u.spectral_density(ref_wavelength), flux density [-] surface brightness, needs a reference wavelength.

  • u.dimensionless_angles(), angle [-] dimensionless (radians to 1).
  • u.mass_energy(), u.brightness_temperature(), niche but real.

Scope the equivalency to the block that needs it rather than enabling it globally:

with u.set_enabled_equivalencies(u.dimensionless_angles()):
    x = (0.5 * u.rad).to(u.dimensionless_unscaled)   # 0.5

3. TypeError on float()/int(): convert to a plain number deliberately

float(3 * u.m) always fails. The fix is to say which unit the number is in, explicitly:

float((3.2 * u.km).to(u.m))    # 3200.0
(3.2 * u.km).to_value(u.m)     # 3200.0 -- plain float, no intermediate Quantity

to_value(unit) is the right API when you want a number out; .value alone returns the number in whatever unit the quantity currently carries, which is often not the unit you assumed.

Dimensionless quantities are the exception, float() works and the scale is folded in (float(3. * u.km / (4. * u.m)) is 750.0). But watch the subtlety: a "dimensionless" quantity like 1. * u.m / u.km has unit m/km with a scale of 0.001. Adding it to a plain float auto-decomposes to scale-free (1. + 1. * u.m / u.km gives 1.001), while .value gives the raw 1.0. If you want the scaled number, call .decompose() first or convert explicitly.

4. Units silently dropped: the numpy boundary

Quantity is an ndarray subclass, and several numpy entry points return a bare ndarray unless asked to preserve the subclass:

q = np.arange(10.) * u.m
np.array(q)                          # bare array -- units GONE (documented)
np.array(q, subok=True)              # keeps the Quantity, units of m
np.broadcast_to(q, (2, 10))          # bare array -- units GONE
np.broadcast_to(q, (2, 10), subok=True)   # keeps units

Same class of bug: calling .value "just to be safe" and then continuing in unit-less code, or feeding a quantity to a library function that internally calls np.asarray without subok=True. When a downstream result is mysteriously off by orders of magnitude, check type(result) and result.unit at the numpy boundary before doubting the physics.

For validating function arguments, u.quantity_input checks that inputs are quantities with units convertible to the declared one, it checks, it does not convert, so myfunction(100 * u.arcsec) still arrives as arcseconds when the declared unit is degrees.

5. Checklist

  1. Read the exception class: UnitConversionError / scalar-conversion TypeError / silent (no exception).

  2. UnitConversionError → run is_equivalent() on both sides. True: wrong operand shape, convert explicitly. False: fix the formula or add an equivalency.

  3. Equivalency needed → pass equivalencies= to .to(), or set_enabled_equivalencies for a block. spectral() does not cover Doppler.

  4. TypeError on float/int → .to(unit).value or .to_value(unit); never float(q) directly on a unit-carrying quantity.

  5. Silent loss → grep the numpy boundary for np.array(, np.broadcast_to, np.asarray without subok=True; check .value is not taken too early.

Evidence

Built from the astropy Quantity documentation (converting to plain Python scalars, dimensionless quantities, quantityinput), the units equivalencies documentation, and astropy's known-issues notes on quantities losing units through np.array/np.broadcastto and on UnitConversionError from dimensionless arithmetic (astropy issues #7582, #7832).

By @issueatlas · Version 2 · Exact version

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_Yrw11BsF2mFPhj7UCYzsvg" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Diagnose and fix astropy Quantity and unit errors <span>— Vectle</span></a>

Diagnose and fix astropy Quantity and unit errors | Vectle