Cannot run my extension in jupythub

I’m writing my own extension. The base was taken from https://github.com/jupyter-server/jupyter_server/tree/main/examples/simple. When trying to start singleuser server I get an error

jupyter-test-5fadmin  | [I 2024-05-13 20:08:17.077 ServerApp] simple_ext2 | extension was successfully linked.
jupyter-test-5fadmin  | Traceback (most recent call last):
jupyter-test-5fadmin  |   File "/opt/conda/bin/jupyterhub-singleuser", line 10, in <module>
jupyter-test-5fadmin  |     sys.exit(main())
jupyter-test-5fadmin  |              ^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/application.py", line 616, in launch_instance
jupyter-test-5fadmin  |     serverapp = cls.initialize_server(argv=args)
jupyter-test-5fadmin  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/application.py", line 586, in initialize_server
jupyter-test-5fadmin  |     serverapp.initialize(
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/traitlets/config/application.py", line 118, in inner
jupyter-test-5fadmin  |     return method(app, *args, **kwargs)
jupyter-test-5fadmin  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/serverapp.py", line 2745, in initialize
jupyter-test-5fadmin  |     point = self.extension_manager.extension_points[starter_extension]
jupyter-test-5fadmin  |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  | KeyError: 'jupyterhub-singleuser'

If I remove the config with the extension startup, everything starts up
c.ServerApp.jpserver_extensions = {"simple_ext2": True}

Which version of JupyterHub are you using?

JupyterHub version 4.1.5
Jupyter Server 2.14.0

Another clarification. I am building my custom docker image.

FROM quay.io/jupyter/base-notebook:latest

ENV PYTHONUNBUFFERED 1

USER ${NB_UID}

COPY /jupyterlab/requirements.txt requirements.txt

RUN pip install -r requirements.txt

Tried another example: Server extension. But I get an error if I use the NB_UID user

0.489 ERROR: Could not install packages due to an OSError: [Errno 13] Permission denied: '/usr/local/bin/myextension_py-0.1.0.tar.gz'
0.489 Consider using the `--user` option or check the permissions.

If I try to use the root user, I get an error

jupyter-test-5fadmin  | [W 2024-05-14 20:36:37.507 ServerApp] notebook_shim | error linking extension: [Errno 13] Permission denied: '/home/jovyan/.local/share/jupyter/runtime'
jupyter-test-5fadmin  |     Traceback (most recent call last):
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 632, in get
jupyter-test-5fadmin  |         value = obj._trait_values[self.name]
jupyter-test-5fadmin  |                 ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
jupyter-test-5fadmin  |     KeyError: 'browser_open_file'
jupyter-test-5fadmin  |     
jupyter-test-5fadmin  |     During handling of the above exception, another exception occurred:
jupyter-test-5fadmin  |     
jupyter-test-5fadmin  |     Traceback (most recent call last):
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 632, in get
jupyter-test-5fadmin  |         value = obj._trait_values[self.name]
jupyter-test-5fadmin  |                 ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
jupyter-test-5fadmin  |     KeyError: 'runtime_dir'
jupyter-test-5fadmin  |     
jupyter-test-5fadmin  |     During handling of the above exception, another exception occurred:
jupyter-test-5fadmin  |     
jupyter-test-5fadmin  |     Traceback (most recent call last):
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/manager.py", line 346, in link_extension
jupyter-test-5fadmin  |         extension.link_all_points(self.serverapp)
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/manager.py", line 228, in link_all_points
jupyter-test-5fadmin  |         self.link_point(point_name, serverapp)
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/manager.py", line 218, in link_point
jupyter-test-5fadmin  |         point.link(serverapp)
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/manager.py", line 140, in link
jupyter-test-5fadmin  |         linker(serverapp)
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/notebook_shim/nbserver.py", line 109, in _link_jupyter_server_extension
jupyter-test-5fadmin  |         members = diff_members(serverapp, nbapp)
jupyter-test-5fadmin  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/notebook_shim/nbserver.py", line 62, in diff_members
jupyter-test-5fadmin  |         m1 = public_members(obj1)
jupyter-test-5fadmin  |              ^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/notebook_shim/nbserver.py", line 56, in public_members
jupyter-test-5fadmin  |         members = inspect.getmembers(obj)
jupyter-test-5fadmin  |                   ^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/inspect.py", line 595, in getmembers
jupyter-test-5fadmin  |         return _getmembers(object, predicate, getattr)
jupyter-test-5fadmin  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/inspect.py", line 573, in _getmembers
jupyter-test-5fadmin  |         value = getter(object, key)
jupyter-test-5fadmin  |                 ^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 687, in __get__
jupyter-test-5fadmin  |         return t.cast(G, self.get(obj, cls))  # the G should encode the Optional
jupyter-test-5fadmin  |                          ^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 635, in get
jupyter-test-5fadmin  |         default = obj.trait_defaults(self.name)
jupyter-test-5fadmin  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 1897, in trait_defaults
jupyter-test-5fadmin  |         return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self))
jupyter-test-5fadmin  |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 1241, in __call__
jupyter-test-5fadmin  |         return self.func(*args, **kwargs)
jupyter-test-5fadmin  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_server/serverapp.py", line 1755, in _default_browser_open_file
jupyter-test-5fadmin  |         return os.path.join(self.runtime_dir, basename)
jupyter-test-5fadmin  |                             ^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 687, in __get__
jupyter-test-5fadmin  |         return t.cast(G, self.get(obj, cls))  # the G should encode the Optional
jupyter-test-5fadmin  |                          ^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 635, in get
jupyter-test-5fadmin  |         default = obj.trait_defaults(self.name)
jupyter-test-5fadmin  |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 1897, in trait_defaults
jupyter-test-5fadmin  |         return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self))
jupyter-test-5fadmin  |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_core/application.py", line 111, in _runtime_dir_default
jupyter-test-5fadmin  |         ensure_dir_exists(rd, mode=0o700)
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/site-packages/jupyter_core/utils/__init__.py", line 26, in ensure_dir_exists
jupyter-test-5fadmin  |         Path(path).mkdir(parents=True, mode=mode)
jupyter-test-5fadmin  |       File "/opt/conda/lib/python3.11/pathlib.py", line 1116, in mkdir
jupyter-test-5fadmin  |         os.mkdir(self, mode)
jupyter-test-5fadmin  |     PermissionError: [Errno 13] Permission denied: '/home/jovyan/.local/share/jupyter/runtime'
jupyter-test-5fadmin  | Traceback (most recent call last):
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 632, in get
jupyter-test-5fadmin  |     value = obj._trait_values[self.name]
jupyter-test-5fadmin  |             ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
jupyter-test-5fadmin  | KeyError: 'runtime_dir'
jupyter-test-5fadmin  | 
jupyter-test-5fadmin  | During handling of the above exception, another exception occurred:
jupyter-test-5fadmin  | 
jupyter-test-5fadmin  | Traceback (most recent call last):
jupyter-test-5fadmin  |   File "/opt/conda/bin/jupyterhub-singleuser", line 10, in <module>
jupyter-test-5fadmin  |     sys.exit(main())
jupyter-test-5fadmin  |              ^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/application.py", line 616, in launch_instance
jupyter-test-5fadmin  |     serverapp = cls.initialize_server(argv=args)
jupyter-test-5fadmin  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/extension/application.py", line 586, in initialize_server
jupyter-test-5fadmin  |     serverapp.initialize(
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/traitlets/config/application.py", line 118, in inner
jupyter-test-5fadmin  |     return method(app, *args, **kwargs)
jupyter-test-5fadmin  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/serverapp.py", line 2754, in initialize
jupyter-test-5fadmin  |     self.init_configurables()
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_server/serverapp.py", line 2064, in init_configurables
jupyter-test-5fadmin  |     "connection_dir": self.runtime_dir,
jupyter-test-5fadmin  |                       ^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 687, in __get__
jupyter-test-5fadmin  |     return t.cast(G, self.get(obj, cls))  # the G should encode the Optional
jupyter-test-5fadmin  |                      ^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 635, in get
jupyter-test-5fadmin  |     default = obj.trait_defaults(self.name)
jupyter-test-5fadmin  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/traitlets/traitlets.py", line 1897, in trait_defaults
jupyter-test-5fadmin  |     return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self))
jupyter-test-5fadmin  |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_core/application.py", line 111, in _runtime_dir_default
jupyter-test-5fadmin  |     ensure_dir_exists(rd, mode=0o700)
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/site-packages/jupyter_core/utils/__init__.py", line 26, in ensure_dir_exists
jupyter-test-5fadmin  |     Path(path).mkdir(parents=True, mode=mode)
jupyter-test-5fadmin  |   File "/opt/conda/lib/python3.11/pathlib.py", line 1116, in mkdir
jupyter-test-5fadmin  |     os.mkdir(self, mode)
jupyter-test-5fadmin  | PermissionError: [Errno 13] Permission denied: '/home/jovyan/.local/share/jupyter/runtime'