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
rustup warns about its own environment? ("warning: default toolchain implicitly overridden") #4936
cargo-update (.../cargo-install-update) runs cargo install to install stuff, so the call-stack is (1) cargo install-update ... -> (2) cargo-install-update -> (3) cargo install. It appears that the rustup cargo wrapper puts the toolchain selected in 1 in the environment so lower layers will obey this configuration (good), understands and obeys it in 3 (good), but now decides to warn about this everything-going-as-designed scenario (bad).
changed the title [-]rustup warns about its own environment?[/-][+]rustup warns about its own environment? ("warning: default toolchain implicitly overridden")[/+]on Jul 2, 2026
Admittedly, I was surprised when I saw the inner cargo proxy setting RUSTUP_TOOLCHAIN_SOURCE to environment. (Note that the environment variable was already set to default.)
Should a proxy set RUSTUP_TOOLCHAIN_SOURCE only when it is not already set?
@smoelius Looking at this issue, it does seem like the default toolchain has been implicitly overridden because now a subprocess (2) is calling back into rustup, which usually doesn't happen. Of course that subprocess can choose whatever active toolchain to call (say it calls cargo +nightly install, how can you tell?).
IMHO you are right that RUSTUP_TOOLCHAIN_SOURCE should be cleaned/reset, but I think it should be that subprocess' responsibility, not cargo's or rustup's?
@nabijaczleweli I would suggest that you tweak RUSTUP_TOOLCHAIN_SOURCE and/or RUSTUP_TOOLCHAIN to your liking before calling back so the problem should be resolved.
@smoelius Looking at this issue, it does seem like the default toolchain has been implicitly overridden because now a subprocess (2) is calling back into rustup, which usually doesn't happen.
I feel like that misrepresents the issue. cargo-install-update is simply calling cargo, which happens to be a Rustup proxy. I suspect that cargo-invoked tools call Rustup proxies all the time.
Moreover, RUSTUP_TOOLCHAIN_SOURCE is kind of an implementation detail. I would argue that common Rust tools should not need to worry about this variable, or even know that it exists.
Regarding your suggestion:
@nabijaczleweli I would suggest that you tweak RUSTUP_TOOLCHAIN_SOURCE and/or RUSTUP_TOOLCHAIN to your liking before calling back so the problem should be resolved.
Which tool should act on the tweaked values, rustup or cargo?
rustup does not seem to check RUSTUP_TOOLCHAIN_SOURCE; rustup only sets it (please correct me if I am wrong).
rustup does check RUSTUP_TOOLCHAIN (that's kind of the problem), but it's not clear what cargo-install-update should set it to, because the user might have set it intentionally.
cargo does check RUSTUP_TOOLCHAIN_SOURCE (again, that's part of the problem). But I would argue that users should not set this variable.
cargo does check RUSTUP_TOOLCHAIN, but again, the user might have set it intentionally.
I am simply having a hard time seeing how cargo-install-update could address this problem.
@smoelius Thanks a lot for the clarification. In that case I agree with you that there is currently no way for either cargo or any cargo plugin to distinguish what is actually going on without leaking abstractions. I propose instead the following change in rustup if it makes sense to you:
If RUST_RECURSION_COUNT exists and has a numerical value that is larger than 0, rustup should not set RUSTUP_TOOLCHAIN_SOURCE. This way, only the top-level proxy call can set that value.
Still I see a downside with that: any binary that calls rustup this way will behave differently in cargo run compared to when it is called directly. In other words we have to assume that the indicated source is always inherited and the nature cannot change in the middle.
@smoelius Sorry, let me take a step back: the root of this issue seems to be the dual meaning of a RUSTUP_TOOLCHAIN override and whether we can see it is overridden by the user or inherited for the sake of coherence.
Since the latter is controlled by rustup itself, maybe we can invent a new reason for that specifically? For example: "set to FOO for inheritance", and once set to that kind of value, the reason itself will not be reset by rustup to "environment".
This way, if RUSTUP_TOOLCHAIN is reset to a different value by the user, cargo will be able to know because FOO is already registered in the env vars.
If RUST_RECURSION_COUNT exists and has a numerical value that is larger than 0, rustup should not set RUSTUP_TOOLCHAIN_SOURCE. This way, only the top-level proxy call can set that value.
I think this idea makes sense. (I considered proposing something like this.)
Since the latter is controlled by rustup itself, maybe we can invent a new reason for that specifically? For example: "set to FOO for inheritance", and once set to that kind of value, the reason itself will not be reset by rustup to "environment".
I'm not sure I follow this idea. "set to FOO for inheritance" would be a new value that RUSTUP_TOOLCHAIN_SOURCE is set to?
I'm not sure I follow this idea. "set to FOO for inheritance" would be a new value that RUSTUP_TOOLCHAIN_SOURCE is set to?
@smoelius Yes, you have understood that correctly.
so the call-stack is (1) cargo install-update ... -> (2) cargo-install-update -> (3) cargo install
My observation here is that (3) relies on the toolchain passed down from (1) via RUSTUP_TOOLCHAIN so the default toolchain is really implicitly overridden as warned by cargo, just to the same value by chance.
Just to make it clearer, I wanted to say that it is currently impossible to distinguish between:
RUSTUP_TOOLCHAIN has been set to FOO because rustup wants its subprocesses to inherit that value.
RUSTUP_TOOLCHAIN has been set to FOO because it's an override from the user.
Currently, both cases would cause a proxy to set RUSTUP_TOOLCHAIN_SOURCE to environment which might not be what you want to see from downstream rustup or cargo, and the intention is partially lost down the chain. So the best thing you can currently do from cargo's perspective is to assume that environment may be an implicit override and warn the user (case 2), even if what actually happened is the case 1.
This semantic difference is best demonstrated in the following scenarios:
A. Imagine a cargo plugin with RUSTUP_TOOLCHAIN=FOO set by rustup upstream calls back into rustup with the implicit active toolchain:
With the current behavior, RUSTUP_TOOLCHAIN_SOURCE is set to environment and a false alarm is triggered.
If we dispatch based on RUST_RECURSION_COUNT, now the count should be larger than zero, so RUSTUP_TOOLCHAIN_SOURCE=default is retained, and we have correctly eliminated a warning.
With the new proposed scheme, rustup knows from RUSTUP_TOOLCHAIN_SOURCE that the upstream was using FOO so it keeps that unchanged, and the downstream knows there hasn't been a conflict between RUSTUP_TOOLCHAIN_SOURCE's FOO and RUSTUP_TOOLCHAIN=FOO.
B. Imagine a cargo plugin with RUSTUP_TOOLCHAIN=FOO set by rustup upstream calls back into rustup with a new active toolchain BAR:
With the current behavior, RUSTUP_TOOLCHAIN_SOURCE is set to environment and the warning is correctly triggered.
If we dispatch based on RUST_RECURSION_COUNT, now the count should be larger than zero, so RUSTUP_TOOLCHAIN_SOURCE=default is retained, and we have swallowed a warning by mistake.
With the new proposed scheme, rustup now knows the distinction between cases 1 and 2. From RUSTUP_TOOLCHAIN_SOURCE, it knows that the upstream was using FOO so it keeps that unchanged. In the meantime, RUSTUP_TOOLCHAIN is updated to BAR, and now the downstream knows there has been an implicit change from FOO to BAR.
Please feel free to correct me if you have spotted anything, I might not be thinking super straight at this point...
But looking back, your current implementation/behavior seems like the simplest at the cost of false alarms from time to time.
B. Imagine a cargo plugin with RUSTUP_TOOLCHAIN=FOO set by rustup upstream calls back into rustup with a new active toolchain BAR:
...
If we dispatch based on RUST_RECURSION_COUNT, now the count should be larger than zero, so RUSTUP_TOOLCHAIN_SOURCE=default is retained, and we have swallowed a warning by mistake.
I see your point.
I'm still not following why RUSTUP_TOOLCHAIN_SOURCE should be "set to FOO for inheritance", though. Why not just "inheritance" or "inherited"? All of the existing values are simple strings that can be explicitly matched. This new one would require something more complicated.
@smoelius Because the downstream would need to know if THE CURRENT value of RUSTUP_TOOLCHAIN is inherited from an upstream rustup, not just whether ANY value has been inherited.
As you said, anyone outside of rustup is not supposed to know what RUSTUP_TOOLCHAIN_SOURCE means, once set to "inherited", it will remain like that while RUSTUP_TOOLCHAIN can be freely swapped in the middle. Once that happens, cargo will look at "inherited" and think this newly-swapped RUSTUP_TOOLCHAIN is inherited from the upstream, so it will not issue the warning: we have a false negative here.
I am not suggesting any specific format we should change the value of those two environment variables to; the above was just an analysis of the minimal information required for this warning to have neither false positives nor false negatives.
This new one would require something more complicated.
I agree that it would imply a complex design by the way, and that's why I'm currently inclined to just not fixing it. Having a few false positives is better than having false negatives, and probably also better than having a much more complex mechanism that is 100% accurate... unless we can come up with something simpler.
I totally get your point. Indeed that would be the simplest solution if RUSTUP_TOOLCHAIN is not guaranteed to be a parsable toolchain name, and that is why I didn't mention it previously.
It seems pretty simple to distinguish since it's rustup talking to itself (or an internal contract between rustup and cargo?
@smoelius I'm wondering on the other hand if this will break anything downstream...
If not, then #4059 has fortunately provided some room for this change by disallowing some toolchain names.
@smoelius Sorry, I was trying to cc you asking if cargo or any downstream tools are relying on RUSTUP_TOOLCHAIN being a parsable toolchain name. I have updated my last comment to make it clearer.
@smoelius Sorry, I was trying to cc you asking if cargo or any downstream tools are relying on RUSTUP_TOOLCHAIN being a parsable toolchain name. I have updated my last comment to make it clearer.
I'm honestly not sure.
My main concern with adding a new RUSTUP_TOOLCHAIN_SOURCE value is whether the new value would cause cargo to issue a warning or not. As best I can tell, a new value would not. Here is the relevant code:
My main concern with adding a new RUSTUP_TOOLCHAIN_SOURCE value is whether the new value would cause cargo to issue a warning or not. As best I can tell, a new value would not.
@smoelius Thanks for the link! Looking at it, I still consider the current warning behavior legit (despite being a bit bothersome), and if we cannot think of an obvious and backwards-compatible way forward based on what we have, we can postpone it until we do...
Doesn't rustup, like. Know what version of cargo it's talking to, so it can choose to degrade in a compatible way for older versions? this feels like a two cakes situation.
Doesn't rustup, like. Know what version of cargo it's talking to, so it can choose to degrade in a compatible way for older versions? this feels like a two cakes situation.
@nabijaczleweli Yes, technically that would be possible, but any changes of that sort will become an explicit maintenance burden. We have hit that case for quite a few times already in rustup (with at least one of them from ten years ago), and we are still paying the debts for this very reason, so I would prefer not to bring anything extra in that regard for just this.
Activity
[-]rustup warns about its own environment?[/-][+]rustup warns about its own environment? ("warning: default toolchain implicitly overridden")[/+]ChrisDenton commentedon Jul 2, 2026
While it's possible rustup could make some improvements, the warning is coming from cargo: https://github.com/rust-lang/cargo/blob/f40cc7a13a8ebe3dd0a35b1e0e37a1e26c8bb0e5/src/cargo/ops/cargo_install.rs#L337-L363
nabijaczleweli commentedon Jul 2, 2026
The usual suspect >_<
Forwarded to rust-lang/cargo#17172
smoelius commentedon Jul 3, 2026
Admittedly, I was surprised when I saw the inner
cargoproxy settingRUSTUP_TOOLCHAIN_SOURCEtoenvironment. (Note that the environment variable was already set todefault.)Should a proxy set
RUSTUP_TOOLCHAIN_SOURCEonly when it is not already set?rami3l commentedon Jul 3, 2026
@smoelius Looking at this issue, it does seem like the default toolchain has been implicitly overridden because now a subprocess (2) is calling back into rustup, which usually doesn't happen. Of course that subprocess can choose whatever active toolchain to call (say it calls
cargo +nightly install, how can you tell?).IMHO you are right that
RUSTUP_TOOLCHAIN_SOURCEshould be cleaned/reset, but I think it should be that subprocess' responsibility, notcargo's orrustup's?@nabijaczleweli I would suggest that you tweak
RUSTUP_TOOLCHAIN_SOURCEand/orRUSTUP_TOOLCHAINto your liking before calling back so the problem should be resolved.smoelius commentedon Jul 3, 2026
I feel like that misrepresents the issue.
cargo-install-updateis simply callingcargo, which happens to be a Rustup proxy. I suspect thatcargo-invoked tools call Rustup proxies all the time.Moreover,
RUSTUP_TOOLCHAIN_SOURCEis kind of an implementation detail. I would argue that common Rust tools should not need to worry about this variable, or even know that it exists.Regarding your suggestion:
Which tool should act on the tweaked values,
rustuporcargo?rustupdoes not seem to checkRUSTUP_TOOLCHAIN_SOURCE;rustuponly sets it (please correct me if I am wrong).rustupdoes checkRUSTUP_TOOLCHAIN(that's kind of the problem), but it's not clear whatcargo-install-updateshould set it to, because the user might have set it intentionally.cargodoes checkRUSTUP_TOOLCHAIN_SOURCE(again, that's part of the problem). But I would argue that users should not set this variable.cargodoes checkRUSTUP_TOOLCHAIN, but again, the user might have set it intentionally.I am simply having a hard time seeing how
cargo-install-updatecould address this problem.rami3l commentedon Jul 3, 2026
@smoelius Thanks a lot for the clarification. In that case I agree with you that there is currently no way for either cargo or any cargo plugin to distinguish what is actually going on without leaking abstractions. I propose instead the following change in rustup if it makes sense to you:
If
RUST_RECURSION_COUNTexists and has a numerical value that is larger than 0, rustup should not setRUSTUP_TOOLCHAIN_SOURCE. This way, only the top-level proxy call can set that value.Still I see a downside with that: any binary that calls rustup this way will behave differently in
cargo runcompared to when it is called directly. In other words we have to assume that the indicated source is always inherited and the nature cannot change in the middle.rami3l commentedon Jul 3, 2026
@smoelius Sorry, let me take a step back: the root of this issue seems to be the dual meaning of a
RUSTUP_TOOLCHAINoverride and whether we can see it is overridden by the user or inherited for the sake of coherence.Since the latter is controlled by rustup itself, maybe we can invent a new reason for that specifically? For example: "set to
FOOfor inheritance", and once set to that kind of value, the reason itself will not be reset by rustup to "environment".This way, if
RUSTUP_TOOLCHAINis reset to a different value by the user,cargowill be able to know becauseFOOis already registered in the env vars.smoelius commentedon Jul 3, 2026
I think this idea makes sense. (I considered proposing something like this.)
I'm not sure I follow this idea. "set to
FOOfor inheritance" would be a new value thatRUSTUP_TOOLCHAIN_SOURCEis set to?rami3l commentedon Jul 4, 2026
@smoelius Yes, you have understood that correctly.
My observation here is that (3) relies on the toolchain passed down from (1) via
RUSTUP_TOOLCHAINso the default toolchain is really implicitly overridden as warned by cargo, just to the same value by chance.Just to make it clearer, I wanted to say that it is currently impossible to distinguish between:
RUSTUP_TOOLCHAINhas been set toFOObecause rustup wants its subprocesses to inherit that value.RUSTUP_TOOLCHAINhas been set toFOObecause it's an override from the user.Currently, both cases would cause a proxy to set
RUSTUP_TOOLCHAIN_SOURCEtoenvironmentwhich might not be what you want to see from downstreamrustuporcargo, and the intention is partially lost down the chain. So the best thing you can currently do fromcargo's perspective is to assume thatenvironmentmay be an implicit override and warn the user (case 2), even if what actually happened is the case 1.This semantic difference is best demonstrated in the following scenarios:
A. Imagine a cargo plugin with
RUSTUP_TOOLCHAIN=FOOset by rustup upstream calls back into rustup with the implicit active toolchain:RUSTUP_TOOLCHAIN_SOURCEis set toenvironmentand a false alarm is triggered.RUST_RECURSION_COUNT, now the count should be larger than zero, soRUSTUP_TOOLCHAIN_SOURCE=defaultis retained, and we have correctly eliminated a warning.RUSTUP_TOOLCHAIN_SOURCEthat the upstream was usingFOOso it keeps that unchanged, and the downstream knows there hasn't been a conflict betweenRUSTUP_TOOLCHAIN_SOURCE'sFOOandRUSTUP_TOOLCHAIN=FOO.B. Imagine a cargo plugin with
RUSTUP_TOOLCHAIN=FOOset by rustup upstream calls back into rustup with a new active toolchainBAR:RUSTUP_TOOLCHAIN_SOURCEis set toenvironmentand the warning is correctly triggered.RUST_RECURSION_COUNT, now the count should be larger than zero, soRUSTUP_TOOLCHAIN_SOURCE=defaultis retained, and we have swallowed a warning by mistake.RUSTUP_TOOLCHAIN_SOURCE, it knows that the upstream was usingFOOso it keeps that unchanged. In the meantime,RUSTUP_TOOLCHAINis updated toBAR, and now the downstream knows there has been an implicit change fromFOOtoBAR.Please feel free to correct me if you have spotted anything, I might not be thinking super straight at this point...
But looking back, your current implementation/behavior seems like the simplest at the cost of false alarms from time to time.
smoelius commentedon Jul 5, 2026
I see your point.
I'm still not following why
RUSTUP_TOOLCHAIN_SOURCEshould be "set to FOO for inheritance", though. Why not just "inheritance" or "inherited"? All of the existing values are simple strings that can be explicitly matched. This new one would require something more complicated.rami3l commentedon Jul 5, 2026
@smoelius Because the downstream would need to know if THE CURRENT value of
RUSTUP_TOOLCHAINis inherited from an upstream rustup, not just whether ANY value has been inherited.As you said, anyone outside of rustup is not supposed to know what
RUSTUP_TOOLCHAIN_SOURCEmeans, once set to "inherited", it will remain like that whileRUSTUP_TOOLCHAINcan be freely swapped in the middle. Once that happens,cargowill look at "inherited" and think this newly-swappedRUSTUP_TOOLCHAINis inherited from the upstream, so it will not issue the warning: we have a false negative here.I am not suggesting any specific format we should change the value of those two environment variables to; the above was just an analysis of the minimal information required for this warning to have neither false positives nor false negatives.
I agree that it would imply a complex design by the way, and that's why I'm currently inclined to just not fixing it. Having a few false positives is better than having false negatives, and probably also better than having a much more complex mechanism that is 100% accurate... unless we can come up with something simpler.
nabijaczleweli commentedon Jul 6, 2026
It seems pretty simple to distinguish since it's rustup talking to itself (or an internal contract between rustup and cargo? either way.):
RUSTUP_TOOLCHAIN=rustup-internal!FOOin situation (1) aboveor
or whatever?
rami3l commentedon Jul 6, 2026
@nabijaczleweli Thanks a lot for your comment.
I totally get your point. Indeed that would be the simplest solution if
RUSTUP_TOOLCHAINis not guaranteed to be a parsable toolchain name, and that is why I didn't mention it previously.@smoelius I'm wondering on the other hand if this will break anything downstream...
If not, then #4059 has fortunately provided some room for this change by disallowing some toolchain names.
smoelius commentedon Jul 7, 2026
@rami3l Did you mean to direct your last comment to
nabijaczleweli, i.e., were you referring to the comment two comments ago?rami3l commentedon Jul 7, 2026
@smoelius Sorry, I was trying to cc you asking if
cargoor any downstream tools are relying onRUSTUP_TOOLCHAINbeing a parsable toolchain name. I have updated my last comment to make it clearer.smoelius commentedon Jul 7, 2026
I'm honestly not sure.
My main concern with adding a new
RUSTUP_TOOLCHAIN_SOURCEvalue is whether the new value would causecargoto issue a warning or not. As best I can tell, a new value would not. Here is the relevant code:rami3l commentedon Jul 7, 2026
@smoelius Thanks for the link! Looking at it, I still consider the current warning behavior legit (despite being a bit bothersome), and if we cannot think of an obvious and backwards-compatible way forward based on what we have, we can postpone it until we do...
nabijaczleweli commentedon Jul 8, 2026
Doesn't rustup, like. Know what version of cargo it's talking to, so it can choose to degrade in a compatible way for older versions? this feels like a two cakes situation.
rami3l commentedon Jul 8, 2026
@nabijaczleweli Yes, technically that would be possible, but any changes of that sort will become an explicit maintenance burden. We have hit that case for quite a few times already in rustup (with at least one of them from ten years ago), and we are still paying the debts for this very reason, so I would prefer not to bring anything extra in that regard for just this.