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
Edit by @code-asher: Storing the state in the browser has (at least) the two following problems:
If you switch to another browser you have to open and configure everything all over again (what this issue was originally about).
It is impossible to seed the initial state like you could in native VS Code by writing to the JSON state file.
Original issue content follows.
OS/Web Information
Web Browser: Chrome v91
Local OS: Windows 10
Remote OS: Ubuntu 20.04
Remote Architecture: Debian
code-server --version: 3.12.0
Steps to Reproduce
Open a new code server instance in browser and make some changes (eg : hide remote host).
Open the same instance in incognito tab.
The changed made above will not be reflected, and you have to make those changes again.
Expected
Till v3.11 the state of code-server was maintained across browsers.
Actual
The state is saved local storage instead of server and hence the changes does not reflect on browser changes.
Notes
scope === StorageScope.GLOBAL ? 'global' : this.payload.id; it is in workbench.web.api.js.map
Perhaps it's related to where the state is saved?
From discussion : #4185
Agreed. I noticed it because I regularly delete all cookies and site data that the browser stores. I don't mind setting an exception for the domains on which code-server is deployed, though.
It doesn't matter whether the state is stored in ~/.local/share/code-server/User/state or the browser 's site data - but it should be documented, which is the case.
👉 In order to reset the state, one has to either delete ~/.local/share/code-server/User/stateor clear the browser's site data.
ℹ️ I had to delete folder ~/.local/share/code-server/User/state after I moved from debian:buster to debian:bullseye, because e.g. the new Python version was not displayed correctly in v3.10.2.
That was a great read. In the past we would periodically run through old issues and close out ones that no longer were applicable (this is because things can change a lot when we update Code versions) and the stale bot moves that burden off us to those who opened the issue. We could just leave them alone but we felt like keeping issues up to date was part of good repository maintenance. Maybe there is a better solution, like labeling issues that are on the Code side with something like upstream and then adding stale or revalidate or something to those when we update Code?
For the browser state I did look into moving it back to the remote file system but it looked non-trivial so I abandoned that effort since we generally try to avoid patches that deviate too aggressively from mainline.
There might be a clean way to do it with a bit more investigation though or maybe upstream would be receptive of a change to make this behavior configurable.
When using Roo Code, settings are lost between browser sessions. @alessandrodd's PR appears to allow some settings to be saved. However, since this PR does not cover SecretStorage, API keys still cannot be persisted.
Gemini suggests using the --password-store=basic option. However, code-server does not support this option. Could enabling the --password-store option serve as a temporary workaround?
In vscode/src/vs/workbench/services/secrets/browser/secretStorageService.ts, there is
// We don't have encryption in the browser so instead we use the// in-memory base class implementation instead.super(true,storageService,encryptionService,logService);
Does this mean code-server always keeps secrets in memory?
secretStorageProvider: config.remoteAuthority&&!secretStorageKeyPath
? undefined/* with a remote without embedder-preferred storage, store on the remote */
: newLocalStorageSecretStorageProvider(secretStorageCrypto),
We patch the secret key path to be /mint-key so in theory this should mean the keys are persisted, I think, but perhaps there is more to the story.
After applying alessandrodd's PR and the following patch, the secrets are stored on the server side.
The patch is generated by AI. I have no idea if this is a "dirty" hack.
To those who want to give it a try: please note that the secrets are stored unencrypted in $HOME/.local/share/code-server/User/globalStorage/state.vscdb.
Index: code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts
===================================================================--- code-server.orig/lib/vscode/src/vs/platform/secrets/common/secrets.ts+++ code-server/lib/vscode/src/vs/platform/secrets/common/secrets.ts@@ -77,8 +77,8 @@ export class BaseSecretStorageService ex
try {
this._logService.trace('[secrets] decrypting gotten secret for key:', fullKey);
- // If the storage service is in-memory, we don't need to decrypt- const result = this._type === 'in-memory'+ // Don't decrypt if storage is in-memory or if encryption service is not available+ const result = this._type === 'in-memory' || !await this._encryptionService.isEncryptionAvailable()
? encrypted
: await this._encryptionService.decrypt(encrypted);
this._logService.trace('[secrets] decrypted secret for key:', fullKey);
@@ -98,8 +98,8 @@ export class BaseSecretStorageService ex
this._logService.trace('[secrets] encrypting secret for key:', key);
let encrypted;
try {
- // If the storage service is in-memory, we don't need to encrypt- encrypted = this._type === 'in-memory'+ // Don't encrypt if storage is in-memory or if encryption service is not available+ encrypted = this._type === 'in-memory' || !await this._encryptionService.isEncryptionAvailable()
? value
: await this._encryptionService.encrypt(value);
} catch (e) {
@@ -136,8 +136,9 @@ export class BaseSecretStorageService ex
private async initialize(): Promise<IStorageService> {
let storageService;
- if (!this._useInMemoryStorage && await this._encryptionService.isEncryptionAvailable()) {- this._logService.trace(`[SecretStorageService] Encryption is available, using persisted storage`);+ if (!this._useInMemoryStorage) {+ // Use persisted storage when not forced to use in-memory+ this._logService.trace(`[SecretStorageService] Using persisted storage`);
this._type = 'persisted';
storageService = this._storageService;
} else {
@@ -145,7 +146,7 @@ export class BaseSecretStorageService ex
if (this._type === 'in-memory') {
return this._storageService;
}
- this._logService.trace('[SecretStorageService] Encryption is not available, falling back to in-memory storage');+ this._logService.trace('[SecretStorageService] Falling back to in-memory storage');
this._type = 'in-memory';
storageService = this._register(new InMemoryStorageService());
}
Index: code-server/lib/vscode/src/vs/workbench/services/secrets/browser/secretStorageService.ts
===================================================================--- code-server.orig/lib/vscode/src/vs/workbench/services/secrets/browser/secretStorageService.ts+++ code-server/lib/vscode/src/vs/workbench/services/secrets/browser/secretStorageService.ts@@ -22,9 +22,9 @@ export class BrowserSecretStorageService
@IBrowserWorkbenchEnvironmentService environmentService: IBrowserWorkbenchEnvironmentService,
@ILogService logService: ILogService
) {
- // We don't have encryption in the browser so instead we use the- // in-memory base class implementation instead.- super(true, storageService, encryptionService, logService);+ // Use remote storage if enabled, otherwise use in-memory storage+ const useRemoteStorage = environmentService.options?.remoteStorageEnabled ?? false;+ super(!useRemoteStorage, storageService, encryptionService, logService);
if (environmentService.options?.secretStorageProvider) {
this._secretStorageProvider = environmentService.options.secretStorageProvider;
Index: code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts
===================================================================--- code-server.orig/lib/vscode/src/vs/code/browser/workbench/workbench.ts+++ code-server/lib/vscode/src/vs/code/browser/workbench/workbench.ts@@ -640,8 +640,8 @@ class WorkspaceProvider implements IWork
})
}
},
- secretStorageProvider: config.remoteAuthority && !secretStorageKeyPath- ? undefined /* with a remote without embedder-preferred storage, store on the remote */+ secretStorageProvider: config.remoteStorageEnabled || (config.remoteAuthority && !secretStorageKeyPath)+ ? undefined /* with remote storage, or with no embedder-prefered storage, store on the remote */
: new LocalStorageSecretStorageProvider(secretStorageCrypto),
});
})();
@hefanbo Can I bother you for build instructions?
I have been trying to use your patch with alessandro's PR but I think I'm getting a mismatch between vscode versions and code-server versions.
Do you remember which version of code-server you aligned with alessandro's PR and your patch?
I'm getting rejected chunks trying to apply this patch too. Any chance you'd want to host your proof of concept branch in your own fork for frame of reference?
I'm getting rejected chunks trying to apply this patch too. Any chance you'd want to host your proof of concept branch in your own fork for frame of reference?
same here, I tried getting as close as I could but no avail.
I tried running alessandro's PR to just use vscode web but some things were still stored in the browser session (user settings, etc)
would appreciate a full branch of your fork or a dockerfile!
Activity
jsjoeio commentedon Sep 21, 2021
Thanks for opening this up @abhay-ranawat! We'll have to investigate
benz0li commentedon Sep 24, 2021
I have the same issue.
It would be great to have this resolved with v3.12.1.
jsjoeio commentedon Sep 24, 2021
That's unlikely to happen given our bandwidth (just setting expectations) but at least we know multiple folks are experiencing this issue.
abhay-ranawat commentedon Sep 24, 2021
Given the changes made in code, everyone should face it (AFAIK) only few might be noticing it.
benz0li commentedon Oct 6, 2021
Agreed. I noticed it because I regularly delete all cookies and site data that the browser stores. I don't mind setting an exception for the domains on which code-server is deployed, though.
It doesn't matter whether the state is stored in
~/.local/share/code-server/User/stateor the browser 's site data - but it should be documented, which is the case.👉 In order to reset the state, one has to either delete
~/.local/share/code-server/User/stateor clear the browser's site data.ℹ️ I had to delete folder
~/.local/share/code-server/User/stateafter I moved fromdebian:bustertodebian:bullseye, because e.g. the new Python version was not displayed correctly in v3.10.2.stale commentedon Apr 4, 2022
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no activity occurs in the next 5 days.
benz0li commentedon Apr 4, 2022
As for stale bot see https://drewdevault.com/2021/10/26/stalebot.html: This is a terrible, horrible, no good, very bad idea.
code-asher commentedon Apr 11, 2022
That was a great read. In the past we would periodically run through old issues and close out ones that no longer were applicable (this is because things can change a lot when we update Code versions) and the stale bot moves that burden off us to those who opened the issue. We could just leave them alone but we felt like keeping issues up to date was part of good repository maintenance. Maybe there is a better solution, like labeling issues that are on the Code side with something like
upstreamand then addingstaleorrevalidateor something to those when we update Code?For the browser state I did look into moving it back to the remote file system but it looked non-trivial so I abandoned that effort since we generally try to avoid patches that deviate too aggressively from mainline.
There might be a clean way to do it with a bit more investigation though or maybe upstream would be receptive of a change to make this behavior configurable.
[-]Maintain state across browsers[/-][+]Maintain state across browsers/sessions[/+]Delete local storage patch
[-]Maintain state across browsers/sessions[/-][+]Store state on remote instead of browser[/+]22 remaining items
hefanbo commentedon Mar 23, 2026
When using Roo Code, settings are lost between browser sessions. @alessandrodd's PR appears to allow some settings to be saved. However, since this PR does not cover SecretStorage, API keys still cannot be persisted.
Gemini suggests using the
--password-store=basicoption. However, code-server does not support this option. Could enabling the--password-storeoption serve as a temporary workaround?hefanbo commentedon Mar 23, 2026
In
vscode/src/vs/workbench/services/secrets/browser/secretStorageService.ts, there isDoes this mean code-server always keeps secrets in memory?
code-asher commentedon Mar 23, 2026
It is supposed to store secrets in browser storage, or at least it used to last I checked.
It looks like while that is the base class, there is the
secretStorageProviderbelow that can still be used to store secrets, and that is set here as long as there is a secret key path: https://github.com/microsoft/vscode/blob/ce099c1ed25d9eb3076c11e4a280f3eb52b4fbeb/src/vs/code/browser/workbench/workbench.ts#L619-L621We patch the secret key path to be
/mint-keyso in theory this should mean the keys are persisted, I think, but perhaps there is more to the story.hefanbo commentedon Mar 24, 2026
After applying alessandrodd's PR and the following patch, the secrets are stored on the server side.
The patch is generated by AI. I have no idea if this is a "dirty" hack.
To those who want to give it a try: please note that the secrets are stored unencrypted in
$HOME/.local/share/code-server/User/globalStorage/state.vscdb.remote-secret-storage.patch
echuber2 commentedon Mar 24, 2026
@hefanbo I think the PR link in your comment is broken. Should it be microsoft/vscode#288880 ?
hefanbo commentedon Mar 24, 2026
Fixed. Thanks!
oransterf commentedon Apr 25, 2026
@hefanbo Can I bother you for build instructions?
I have been trying to use your patch with alessandro's PR but I think I'm getting a mismatch between vscode versions and code-server versions.
Do you remember which version of code-server you aligned with alessandro's PR and your patch?
hefanbo commentedon Apr 27, 2026
@oransterf
Please try the following patch on 44fc463
I applied some other patches before this one, so there might be offsets when you apply it.
remote-storage.patch
echuber2 commentedon May 1, 2026
I'm getting rejected chunks trying to apply this patch too. Any chance you'd want to host your proof of concept branch in your own fork for frame of reference?
oransterf commentedon May 1, 2026
same here, I tried getting as close as I could but no avail.
I tried running alessandro's PR to just use vscode web but some things were still stored in the browser session (user settings, etc)
would appreciate a full branch of your fork or a dockerfile!
hefanbo commentedon May 2, 2026
I'm on vacation now and will be back in a few days with my fork.
hefanbo commentedon May 6, 2026
Please try my fork @echuber2 @oransterf
oransterf commentedon May 7, 2026
It worked, thank you so much!
fix: persist workbench state on the remote