You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
JAX-fitting a shapelet model crashes when autofit flattens the model instance into a pytree. Surfaced by the 2026-07-13 release-validation Stage-3 run (PyAutoHeart workspace-validation run_id=29266305445, TestPyPI 2026.7.13.1.dev65501) — autogalaxy imaging scripts/imaging/features/shapelets/modeling.py FAILs under the JAX release profile in jax.vmap(jax.jit(self.call)) (Fitness._vmap).
Root cause (diagnosed — differs from the prompt's initial hypothesis)
The prompt guessed a __slots__/array-like component. The real cause is erroneous registration of a leaf type:
af.Model(ShapeletPolar) auto-wraps its int-typed constructor args n/m as af.Model(int) sub-models.
register_model._walk (autofit/jax/pytrees.py) registers everyModel.cls it walks as a JAX pytree node — including builtins.int.
Once int is a registered pytree node, JAX calls the instance-flatten _partition(5) on every int leaf (n, m, id, pytree_token), which does vars(5) → TypeError: vars() argument must have __dict__ attribute.
int (like float/str/bool) is a native JAX leaf — it must never be registered as a pytree container. Reproduced in pure autofit (no autogalaxy) via af.Model(int) as a sub-model → int in _REGISTERED_INSTANCE_CLASSES → tree_flatten crashes. The Basis/ShapeletPolar/Galaxy instances themselves all have __dict__ and flatten fine.
Fix (at the producer, per no-silent-guards)
Gate registration in _walk: only register cls whose instances carry a __dict__ — any("__dict__" in vars(k) for k in cls.__mro__). This cleanly excludes int/float/str/bool/NoneType/tuple (native leaves, left opaque) and any purely __slots__ class (correctly treated as an opaque leaf, matching the prompt's "treat as opaque leaf as appropriate"), while still registering real model-component classes. No silent fallback inside _partition — the erroneous registration simply never happens.
Plan
autofit/jax/pytrees.py: add _instances_carry_dict(cls) helper; in register_model._walk, skip the register_pytree_node block for classes that fail it (leave classifier/ctor-arg bookkeeping intact). Comment the reasoning.
Regression assertion in autofit_workspace_test/scripts/jax_assertions/ (JAX unit tests were moved out of test_autofit/ in test: delete jax-using unit tests (moved to autofit_workspace_test) #1247): build a model with an af.Model(int) sub-model, register_model, assert int/float are NOT registered and jax.tree_util.tree_flatten(instance) round-trips.
Verify the crash is gone and the shapelet-shaped tree flattens.
Detailed implementation plan
Work Classification
Library + Workspace (library-first).
Affected Repositories
PyAutoLabs/PyAutoFit (primary — the _walk registration guard)
Verify against the reproduction (crash gone; int not registered; flatten OK).
Traceback (as reported)
autofit/non_linear/fitness.py:486 func = jax.vmap(jax.jit(self.call))
autofit/jax/pytrees.py:168 (flatten) -> :152 (_partition)
for name, value in vars(instance).items():
TypeError: vars() argument must have __dict__ attribute
Autonomy
--auto, effective level supervised (bug work-type cap). Plan written here; run parks at ship sign-off with a question rather than opening the PR. Merge/close remain human.
Original Prompt
Click to expand starting prompt
JAX pytree _partition crashes on instances without dict (vars() TypeError) during vmap/jit
Type: bug
Target: autofit
Repos:
PyAutoFit
Difficulty: medium
Autonomy: supervised
Priority: high
Status: formalised
JAX-fitting a shapelet model crashes when autofit flattens the model instance into a
pytree. Surfaced by the 2026-07-13 release-validation Stage-3 run (PyAutoHeart
workspace-validation run_id=29266305445, TestPyPI 2026.7.13.1.dev65501) — autogalaxy
imaging scripts/imaging/features/shapelets/modeling.py FAIL under the release env profile
(JAX enabled).
Traceback:
scripts/imaging/features/shapelets/modeling.py:424 result = search.fit(model=model, analysis=analysis)
autofit/non_linear/search/nest/nautilus/search.py:189 fitness = Fitness(...)
autofit/non_linear/fitness.py:134 self._call = self._vmap
autofit/non_linear/fitness.py:486 func = jax.vmap(jax.jit(self.call))
autofit/jax/pytrees.py:168 (flatten) -> :152 (_partition)
for name, value in vars(instance).items():
TypeError: vars() argument must have __dict__ attribute
Root cause — autofit/jax/pytrees.py:152 (_partition) assumes every model instance /
component exposes __dict__; it calls vars(instance) unconditionally. A shapelet model
carries a component whose instance has no __dict__ (e.g. __slots__-based or an
array-like leaf), so vars() raises. This blocks jax.vmap(jax.jit(self.call)) in Fitness._vmap, i.e. any JAX-accelerated fit whose model contains such a component.
Only exercised under the JAX/release profile (the curated smoke subset does not JAX-fit
shapelets), so the nightly release would not catch it — but it breaks JAX shapelet fitting
for users. Fix _partition to handle no-__dict__ instances (fall back to __slots__ traversal / treat as an opaque leaf as appropriate) rather than assuming vars(); add a JAX pytree-flatten unit test covering a slotted/array-like component.
Do NOT paper over it with a silent guard — see [[feedback_no_silent_guards]]. Cross-check
against the existing pytree PoC work ([[register_and_iterate]] history) for the intended
partition contract.
Overview
JAX-fitting a shapelet model crashes when autofit flattens the model instance into a pytree. Surfaced by the 2026-07-13 release-validation Stage-3 run (PyAutoHeart workspace-validation
run_id=29266305445, TestPyPI2026.7.13.1.dev65501) —autogalaxyimagingscripts/imaging/features/shapelets/modeling.pyFAILs under the JAX release profile injax.vmap(jax.jit(self.call))(Fitness._vmap).Root cause (diagnosed — differs from the prompt's initial hypothesis)
The prompt guessed a
__slots__/array-like component. The real cause is erroneous registration of a leaf type:af.Model(ShapeletPolar)auto-wraps itsint-typed constructor argsn/masaf.Model(int)sub-models.register_model._walk(autofit/jax/pytrees.py) registers everyModel.clsit walks as a JAX pytree node — includingbuiltins.int.intis a registered pytree node, JAX calls the instance-flatten_partition(5)on everyintleaf (n,m,id,pytree_token), which doesvars(5)→TypeError: vars() argument must have __dict__ attribute.int(likefloat/str/bool) is a native JAX leaf — it must never be registered as a pytree container. Reproduced in pure autofit (no autogalaxy) viaaf.Model(int)as a sub-model →intin_REGISTERED_INSTANCE_CLASSES→tree_flattencrashes. TheBasis/ShapeletPolar/Galaxyinstances themselves all have__dict__and flatten fine.Fix (at the producer, per no-silent-guards)
Gate registration in
_walk: only registerclswhose instances carry a__dict__—any("__dict__" in vars(k) for k in cls.__mro__). This cleanly excludesint/float/str/bool/NoneType/tuple(native leaves, left opaque) and any purely__slots__class (correctly treated as an opaque leaf, matching the prompt's "treat as opaque leaf as appropriate"), while still registering real model-component classes. No silent fallback inside_partition— the erroneous registration simply never happens.Plan
autofit/jax/pytrees.py: add_instances_carry_dict(cls)helper; inregister_model._walk, skip theregister_pytree_nodeblock for classes that fail it (leave classifier/ctor-arg bookkeeping intact). Comment the reasoning.autofit_workspace_test/scripts/jax_assertions/(JAX unit tests were moved out oftest_autofit/in test: delete jax-using unit tests (moved to autofit_workspace_test) #1247): build a model with anaf.Model(int)sub-model,register_model, assertint/floatare NOT registered andjax.tree_util.tree_flatten(instance)round-trips.Detailed implementation plan
Work Classification
Library + Workspace (library-first).
Affected Repositories
_walkregistration guard)Branch Survey
Suggested branch:
feature/jax-pytree-leaf-registrationWorktree root:
~/Code/PyAutoLabs-wt/jax-pytree-leaf-registration/Implementation Steps
PyAutoFit/autofit/jax/pytrees.py— helper_instances_carry_dict(cls)and gate theregister_pytree_nodeblock in_walkon it.autofit_workspace_test/scripts/jax_assertions/pytree_leaf_registration.py(new) — reproduceaf.Model(int)sub-model; assert no leaf-type registration +tree_flattenround-trip.intnot registered; flatten OK).Traceback (as reported)
Autonomy
--auto, effective level supervised (bug work-type cap). Plan written here; run parks at ship sign-off with a question rather than opening the PR. Merge/close remain human.Original Prompt
Click to expand starting prompt
JAX pytree _partition crashes on instances without dict (vars() TypeError) during vmap/jit
Type: bug
Target: autofit
Repos:
Difficulty: medium
Autonomy: supervised
Priority: high
Status: formalised
JAX-fitting a shapelet model crashes when autofit flattens the model instance into a
pytree. Surfaced by the 2026-07-13 release-validation Stage-3 run (PyAutoHeart
workspace-validation
run_id=29266305445, TestPyPI2026.7.13.1.dev65501) —autogalaxyimaging
scripts/imaging/features/shapelets/modeling.pyFAIL under the release env profile(JAX enabled).
Traceback:
Root cause —
autofit/jax/pytrees.py:152(_partition) assumes every model instance /component exposes
__dict__; it callsvars(instance)unconditionally. A shapelet modelcarries a component whose instance has no
__dict__(e.g.__slots__-based or anarray-like leaf), so
vars()raises. This blocksjax.vmap(jax.jit(self.call))inFitness._vmap, i.e. any JAX-accelerated fit whose model contains such a component.Only exercised under the JAX/release profile (the curated smoke subset does not JAX-fit
shapelets), so the nightly release would not catch it — but it breaks JAX shapelet fitting
for users. Fix
_partitionto handle no-__dict__instances (fall back to__slots__traversal / treat as an opaque leaf as appropriate) rather than assumingvars(); add a JAX pytree-flatten unit test covering a slotted/array-like component.Do NOT paper over it with a silent guard — see [[feedback_no_silent_guards]]. Cross-check
against the existing pytree PoC work ([[register_and_iterate]] history) for the intended
partition contract.