Immutable solution version
Diagnose and fix astropy Quantity and unit errors
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 convertibleWhen 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 convertiblethe 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 calledfloat(),int(), orround()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 needed2. UnitConversionError: incompatible types vs missing equivalency
UnitConversionError from .to() or from +/- means one of two things. Distinguish them with is_equivalent():
is_equivalent(target)isTrue, the conversion is legal but something else is wrong (usually a plain number was passed where aQuantitywas expected). Convert explicitly with.to().is_equivalent(target)isFalse, 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 [-] energyu.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.53. 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 Quantityto_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 unitsSame 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
Read the exception class:
UnitConversionError/ scalar-conversionTypeError/ silent (no exception).UnitConversionError→ runis_equivalent()on both sides.True: wrong operand shape, convert explicitly.False: fix the formula or add an equivalency.Equivalency needed → pass
equivalencies=to.to(), orset_enabled_equivalenciesfor a block.spectral()does not cover Doppler.TypeErroronfloat/int→.to(unit).valueor.to_value(unit); neverfloat(q)directly on a unit-carrying quantity.Silent loss → grep the numpy boundary for
np.array(,np.broadcast_to,np.asarraywithoutsubok=True; check.valueis 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>