Note
Grok responding on behalf of Julius.
Thanks for the detailed report. I checked it against main at d7202109, and the diagnosis holds.
Confirmed on main
sessionGrantsScopereturnssession.permissions.includes(scope)whenever the server sendspermissions(L186). ThelegacyParentsfallback (environment:maintain→orchestration:operate, L154-L164) only runs against servers that send neitherpermissionsnorauth.serverUpdateScope.- Upgraded servers send the stored grant as-is.
getSessionStatespreadsauthScopeResponse(session.scopes), which setspermissionsto the stored scopes. #10298, which landed with #9786, deliberately removed scope expansion ("Existing credentials keep their recorded grants"). A session paired with the old five scopes therefore has noenvironment:maintain. - The server would refuse the update anyway.
RpcAuthorization.tsL77-L79 requiresenvironment:maintainforserver.updateServer/updateServerWithProgress, checked against the session's stored scopes (ws.ts L3159). So the client-side gate itself is consistent with the server. - Banner / row button:
canUpdatefeedsdisabled={manualCommand === null && !canUpdate}(L333, and L316 for the icon variant). Nothing explains why it's disabled. The icon variant's tooltip only shows the action label, and the composer banner's description is the genericserverUpdateGuidance("Update to stay in sync"). - "Update all":
savedServerUpdateTargetsdoesn't look at the session's permissions.ServerUpdatesActiononly filters onselfUpdateand disables only wheneligible.length === 0(L159). On click,useServerUpdatereturns early whencanUpdateServeris false, before the RPC and before any toast. That matches the silent no-op you saw. - The only hint is
PermissionUpdateNotice. It's a one-time toast whose dismissal is persisted in localStorage (t3code:permission-update:v1:<environmentId>), so after it's dismissed the update UI gives no clue.
Root cause
The permission split (#9786 / #10298) intentionally leaves pre-split sessions without environment:maintain, and the update UI gates on that permission without telling anyone. The single button just greys out, and the bulk button counts targets it will then skip without saying so. Your 2752 → 2761 update succeeding fits this: the client's legacy fallback applies to servers that don't advertise the new fields. I haven't verified exactly which release tags carry which commits.
Possible fixes (untested)
- Surface the reason (safe part). When the button is disabled because
environment:maintainis missing, show something like "This connection needs to be paired again to update the server", ideally with an "Open Connections" action. Do it in bothServerUpdateActionvariants and in the banner description.sessionHasLegacyPermissionscould word it specifically for pre-split pairings. - Make "Update all" honest. Either leave targets without
environment:maintainout ofsavedServerUpdateTargets(so the button hides or disables when none qualify), or have the click toast which servers were skipped and why, instead of returning silently. - Letting old sessions update again would mean treating
orchestration:operateas grantingenvironment:maintainfor legacy grants. The server enforces this too, so the change would have to be server-side as well. That widens what existing credentials can do and reverses an explicit decision in #10298, so it's a security/product call for the maintainers, not a straightforward bug fix.
Workaround
Pair the environment again with a fresh link (Settings → Connections → Add Environment with the new link or code; see remote-access.md). Pair through the same address you use now, because saved credentials are per route and other routes can keep the old grant (see #17014). Updating on the host directly, as you did with t3 update, also gets around it.
Related
- #6204 (open, currently conflicting) adds a disabled-state tooltip to
ServerUpdateAction, but only for "not connected yet". It doesn't cover permissions, though the same tooltip pattern could carry this reason. - #13072 may involve the same gate for older Tailscale pairings. Not confirmed.
- #16804 is the same family (missing
providers:manage), but on freshly issued mobile sessions, so it's a different cause. - #17013 is another settings regression from #9786, with an unrelated mechanism.
- #15835 is a different update-guidance gate (incompatible environments).