@@ -639,7 +639,18 @@ def __init__(self, options):
639639# Do this last since it relies on other attributes
640640self .info = self ._get_app_info ()
641641# Migrate from 4.0 which did not have "locked" status
642- self ._maybe_mirror_disabled_in_locked ()
642+ try :
643+ self ._maybe_mirror_disabled_in_locked (level = "sys_prefix" )
644+ except PermissionError :
645+ try :
646+ self .logger .info (
647+ "`sys_prefix` level settings are read-only, using `user` level for migration to `lockedExtensions`"
648+ )
649+ self ._maybe_mirror_disabled_in_locked (level = "user" )
650+ except PermissionError :
651+ self .logger .warning (
652+ "Both `sys_prefix` and `user` level settings are read-only, cannot auto-migrate `disabledExtensions` to `lockedExtensions`"
653+ )
643654
644655def install_extension (self ,extension ,existing = None ,pin = None ):
645656"""Install an extension package into JupyterLab.
@@ -1130,7 +1141,7 @@ def _maybe_mirror_disabled_in_locked(self, level="sys_prefix"):
11301141app_settings_dir = app_settings_dir ,logger = self .logger ,level = level
11311142 )
11321143if "lockedExtensions" in page_config :
1133- # short-circut if migration already happened
1144+ # short-circuit if migration already happened
11341145return False
11351146
11361147# copy disabled onto lockedExtensions, ensuring the mapping format