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
{{ message }}
Repository navigation
from_pretrained loads wrong custom module after save_pretrained #45698
This correctly prints Magic A from pretrained_a and Magic B from pretrained_b:
Load "pretrained_a"
Model says: Magic A
Source path: HF_MODULES_CACHE/transformers_modules/pretrained_a/custom_model.py
Source says: Magic A
Load "pretrained_b"
Model says: Magic B
Source path: HF_MODULES_CACHE/transformers_modules/pretrained_b/custom_model.py
Source says: Magic B
3. Failing case: saving first changes the later load
Expected result: pretrained_b should be loaded from HF_MODULES_CACHE/transformers_modules/pretrained_b/custom_model.py and print Magic B, like it does in the control case.
@Rocketknight1 This looks related to #45642, but I think it is a different problem.
#45642 fixes collisions inside the dynamic module cache: two different local model directories could previously map to the same cached module path. After that PR, the control case correctly gets distinct hashed cache paths, e.g.
This issue is not that pretrained_a and pretrained_b collide in the dynamic module cache. In the failing case, Transformers does not reach the dynamic module cache for pretrained_b at all. After saving/registering the local custom model earlier in the same Python process, AutoModel.from_pretrained(..., trust_remote_code=True) resolves to the already-registered local custom_model.py class instead of loading the class declared by pretrained_b's auto_map.
So #45642 changes the expected cached source path, but the failing behavior remains:
Yeah, this does seem like a real bug. I think it was introduced in #45094 - cc @HanFa@hmellor. I can try drafting a fix, but if anyone has touched this code recently and can see an obvious approach, let me know!
My plan is to add a small exception in AutoConfig.from_pretrained that if the local directory already contains the module file referenced in auto_map, it should use that saved module instead of any globally registered class for the same model_type.
@nurpax i tried to reproduce this on transformers==5.7.0.dev0 with a clean environment (Python 3.12 CPU-only)
Both the control case and the failing case behave correctly for me:
I'm a little confused, if you don't want AutoConfig to use the class that was explicitly registered using AutoConfig.register with model_type="custom", why are you registering it?
I think the core issue is that AutoConfig.register() / AutoModel.register() are process-global, while auto_map is checkpoint-local.
Once a package import has registered a model_type, that registration affects every later from_pretrained() call in the same process. But the desired code-resolution policy is often per checkpoint.
For some loads, registered/local code should win: local debugging, patched installed code, or trust_remote_code=False.
For others, the checkpoint's auto_map should win: the checkpoint may point to the exact code snapshot saved with that checkpoint, and using the current process's registered implementation can silently load incompatible code.
I don't think this is an unusual edge case. The docs show Auto*.register() as the way to integrate custom models with Auto classes, while register_for_auto_class() / auto_map is the way to make saved custom checkpoints reloadable/shareable. So users naturally end up in environments where:
a model type is globally registered in the current process, and
checkpoints also contain auto_map metadata pointing at checkpoint-specific code.
The precedence between these two mechanisms - process-global registration and checkpoint-local auto_map metadata - does not appear to be clearly documented, which makes mixed use semantics ambiguous.
Maybe the fix is not to change the default, but to expose the precedence explicitly, for example with a per-call option likeprefer_remote_code=False (or prefer_auto_map=True?), while preserving the current default behavior.
I still think the point in my above comment stands. @sebastianvlad1, if you're interested in updating your PR, I'd go for the prefer_auto_map right away, since that's a more general solution to this issue.
We have cases in our production training code where we could use the extra control. But I can't speak on behalf of the maintainers if they're interested in this or not.
For others, the checkpoint's auto_map should win: the checkpoint may point to the exact code snapshot saved with that checkpoint, and using the current process's registered implementation can silently load incompatible code.
Actually, the reason for #45094 is because the code in checkpoints is often {stale/broken on newer Transformers} and we want the register to override it.
This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.
Please note that issues that do not follow the contributing guidelines are likely to be ignored.
Activity
Rocketknight1 commentedon Apr 29, 2026
Since it's a related area, can you rebase after #45642 is merged and check the issue is still present?
nurpax commentedon Apr 29, 2026
@Rocketknight1 This looks related to #45642, but I think it is a different problem.
#45642 fixes collisions inside the dynamic module cache: two different local model directories could previously map to the same cached module path. After that PR, the control case correctly gets distinct hashed cache paths, e.g.
This issue is not that
pretrained_aandpretrained_bcollide in the dynamic module cache. In the failing case, Transformers does not reach the dynamic module cache forpretrained_bat all. After saving/registering the local custom model earlier in the same Python process,AutoModel.from_pretrained(..., trust_remote_code=True)resolves to the already-registered localcustom_model.pyclass instead of loading the class declared bypretrained_b'sauto_map.So #45642 changes the expected cached source path, but the failing behavior remains:
Expected:
HF_MODULES_CACHE/transformers_modules/pretrained_b/<hash>/custom_model.pyActual:
custom_model.pynurpax commentedon Apr 29, 2026
Sorry, forgot to include in the previous comment, that I did also test on the latest main with the fixes. The issue is still present!
Rocketknight1 commentedon Apr 30, 2026
Yeah, this does seem like a real bug. I think it was introduced in #45094 - cc @HanFa @hmellor. I can try drafting a fix, but if anyone has touched this code recently and can see an obvious approach, let me know!
sebastianvlad1 commentedon Apr 30, 2026
Hi @Rocketknight1, I've already started working on this if you don't mind me taking a shot at it.
sebastianvlad1 commentedon Apr 30, 2026
My plan is to add a small exception in AutoConfig.from_pretrained that if the local directory already contains the module file referenced in auto_map, it should use that saved module instead of any globally registered class for the same model_type.
Prachi-kushwaha commentedon May 2, 2026
@nurpax i tried to reproduce this on transformers==5.7.0.dev0 with a clean environment (Python 3.12 CPU-only)
Both the control case and the failing case behave correctly for me:
nurpax commentedon May 4, 2026
Hi @Prachi-kushwaha, I can repro the bug using the latest transformers main as follows.
The "Model says", "Source says" lines do not match the outputs of the control case.
hmellor commentedon May 5, 2026
I'm a little confused, if you don't want
AutoConfigto use the class that was explicitly registered usingAutoConfig.registerwithmodel_type="custom", why are you registering it?nurpax commentedon May 6, 2026
I think the core issue is that
AutoConfig.register()/AutoModel.register()are process-global, whileauto_mapis checkpoint-local.Once a package import has registered a
model_type, that registration affects every laterfrom_pretrained()call in the same process. But the desired code-resolution policy is often per checkpoint.For some loads, registered/local code should win: local debugging, patched installed code, or
trust_remote_code=False.For others, the checkpoint's
auto_mapshould win: the checkpoint may point to the exact code snapshot saved with that checkpoint, and using the current process's registered implementation can silently load incompatible code.I don't think this is an unusual edge case. The docs show
Auto*.register()as the way to integrate custom models with Auto classes, whileregister_for_auto_class()/auto_mapis the way to make saved custom checkpoints reloadable/shareable. So users naturally end up in environments where:auto_mapmetadata pointing at checkpoint-specific code.The precedence between these two mechanisms - process-global registration and checkpoint-local
auto_mapmetadata - does not appear to be clearly documented, which makes mixed use semantics ambiguous.Maybe the fix is not to change the default, but to expose the precedence explicitly, for example with a per-call option like
prefer_remote_code=False(orprefer_auto_map=True?), while preserving the current default behavior.sebastianvlad1 commentedon May 6, 2026
Let me know if my PR looks good or if you’d prefer I go with an explicit prefer_auto_map parameter instead.
sebastianvlad1 commentedon May 20, 2026
Hi @Rocketknight1 @Cyrilvallez , just checking in to see if there's still interest in getting this fixed. Happy to help in any way!
nurpax commentedon May 27, 2026
I still think the point in my above comment stands. @sebastianvlad1, if you're interested in updating your PR, I'd go for the
prefer_auto_mapright away, since that's a more general solution to this issue.We have cases in our production training code where we could use the extra control. But I can't speak on behalf of the maintainers if they're interested in this or not.
hmellor commentedon May 27, 2026
Actually, the reason for #45094 is because the code in checkpoints is often {stale/broken on newer Transformers} and we want the
registerto override it.sebastianvlad1 commentedon May 29, 2026
@nurpax I’ve made the PR update already. If you have time, feel free to have a look and tell me if anything should be changed.
github-actions commentedon Jun 23, 2026
This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.
Please note that issues that do not follow the contributing guidelines are likely to be ignored.