Skip to content

subtract_dark(scale=True): device-propagation bug misreported as a unit mismatch under array-api-strict #966

Description

@mwcraig

subtract_dark(..., scale=True) fails under CCDPROC_ARRAY_LIBRARY=array-api-strict with a UnitsError, but the units involved are identical ('adu' == 'adu') — the message is misleading. 4/9 parametrized cases in test_subtract_dark fail: exactly the four with scale=True (explicit_times/exposure_keyword don't matter).

FAILED test_subtract_dark[True-True-True]
FAILED test_subtract_dark[True-True-False]
FAILED test_subtract_dark[True-False-True]
FAILED test_subtract_dark[True-False-False]
E   astropy.units.errors.UnitsError: Unit 'adu' of the uncalibrated image
    does not match unit 'adu' of the calibration image
ccdproc/core.py:862: UnitsError

Root cause (note: the #941 table called this a "unit-mismatch/device issue" — the unit-mismatch half is wrong; it is purely a device-propagation bug). In ccdproc/core.py:855 (branch array-api-strict-triage-tooling), the scale-factor array is built without a device argument:

_master_scaled = _master_scaled.multiply(xp.asarray(scale_factor))

The test harness places fixture arrays on non-default device1 (see ccdproc/conftest.py), but xp.asarray(scale_factor) defaults to CPU_DEVICE. The elementwise multiply then raises:

ValueError: Arrays from two different devices (array_api_strict.Device('device1')
and array_api_strict.Device('CPU_DEVICE')) can not be combined.

The broad except (u.UnitsError, u.UnitConversionError, ValueError) at core.py:859 swallows that ValueError and re-raises it as a bogus UnitsError about non-matching units, masking the real problem. This is the same class of bug a CuPy user would hit as a device-to-host error.

Suggested fix: construct the scale-factor array on the same device as the data (e.g. pass device= from the master's array), and narrow the blanket ValueError catch at core.py:859 so genuine non-unit failures aren't relabeled as unit errors.

Part of the array-API triage in #941; found with the array-api-strict tooling from #937/#939. Verified at branch tip d329ac5 (2026-08-01); the true underlying exception was confirmed by reproducing the scale=True path directly, bypassing the catch-all.

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions