huggingface / huggingface/diffusers
`register_to_config` mislabels positional `__init__` args as `_use_default_values`, so `from_config` round trips silently revert them to defaults
- Dominant language
- Python
- Stars
- 34.5k
- Forks
- 7.3k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 91
Description
### Describe the bug
`@register_to_config` computes `_use_default_values` as `set(new_kwargs) - set(init_kwargs)`, but `init_kwargs` only contains *keyword* arguments (`src/diffusers/configuration_utils.py:725-726`). Any constructor argument passed **positionally** is mislabeled as "used default value", and `extract_init_dict` then strips it on every `from_config` round trip (`configuration_utils.py:500-501`).
- Expected: per the comment at `configuration_utils.py:499` ("Skip keys that were *not present* in the original config, so default `__init__` values were used") and the design intent in https://github.com/huggingface/diffusers/pull/3929#issuecomment-1618919655, `_use_default_values` should only contain parameters the caller did not provide — positional and keyword calls should round-trip identically.
- Actual: the config *displays* the explicitly-set value, but `from_config(obj.config)` (the documented scheduler-swap pattern) silently reverts it to the class default. Affects every `ConfigMixin` subclass.
I'd be happy to open a PR: exclude positionally-bound parameter names from the `_use_default_values` computation in `inner_init` (a two-line change), plus a regression test in `tests/others/test_config.py` — once a maintainer acks, per the AI-assisted contributions guidelines.
### Reproduction
```python
from diffusers import DDIMScheduler, EulerDiscreteScheduler
s = DDIMScheduler(500) # positional, explicit non-default value
print(s.config.num_train_timesteps) # 500
print("num_train_timesteps" in s.config["_use_default_values"]) # True <-- mislabeled
print(DDIMScheduler.from_config(s.config).config.num_train_timesteps) # 1000, expected 500
print(EulerDiscreteScheduler.from_config(s.config).config.num_train_timesteps) # 1000, expected 500
k = DDIMScheduler(num_train_timesteps=500) # keyword control group
print(DDIMScheduler.from_config(k.config).config.num_train_timesteps) # 500, correct
```
### Logs
```shell
(no traceback — the failure mode is a silently wrong value)
```
### System Info
- 🤗 Diffusers version: 0.40.0.dev0 (`main` @ 614ae4b)
- Platform: macOS-26.5.2-arm64-arm-64bit-Mach-O
- Python version: 3.13.3
- PyTorch version (GPU?): 2.13.0 (False)
- Huggingface_hub version: 1.27.0
- Transformers version: 5.15.0
- Safetensors version: 0.8.0
- Using GPU in script?: No
### Who can help?
_No response_
---
Disclosure: this report was prepared with AI assistance; I reproduced the issue locally and reviewed every claim myself.
Contributor guide
Research direction
Start in src/diffusers/configuration_utils.py around inner_init at lines 725-726 and inspect extract_init_dict around lines 499-501. Run the reproduction and add the regression coverage in tests/others/test_config.py. Done means positional and keyword constructor arguments both preserve their explicit values through from_config round trips.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- developer-experience
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100