Skip to content

jupyterlab: empty base_url passes an empty positional arg that overrides ServerApp.root_dir (subdomain = true) #1026

Description

@spapa013

Module name and version

coder/jupyterlab v1.2.2 (same code on main).

Expected vs. actual behavior

Expected: with config setting ServerApp.root_dir, JupyterLab serves from that directory.

Actual: the configured root_dir is silently ignored and JupyterLab always serves the launch cwd (e.g. /home/coder). allow_root from the same config is applied, so the config file is being read — only root_dir is lost.

Minimal reproduction case

Use the module with subdomain = true and a root set via config:

module "jupyterlab" {
  source   = "registry.coder.com/coder/jupyterlab/coder"
  version  = "1.2.2"
  agent_id = coder_agent.main.id
  config   = jsonencode({ ServerApp = { root_dir = "/" } })
}

Start the workspace, then inspect the process and log:

$ ps -ef | grep '[j]upyter-lab'
… jupyter-lab --no-browser  --ServerApp.ip=* --ServerApp.port=19999 …

$ grep "Serving notebooks" /tmp/jupyterlab.log
Serving notebooks from local directory: /home/coder

Note the double space after --no-browser (an empty "" positional) and the absence of --ServerApp.root_dir.

Error messages

None — the failure is silent. Jupyter treats the empty positional as a directory to open; it resolves to the process cwd and overrides root_dir from the config file.

Environment details

  • OS: Linux (Coder Kubernetes provisioner)
  • Terraform: 1.15.5
  • Coder provider: v2.18.0
  • Jupyter Server: 2.17.0 (JupyterLab from an image-provided /opt/venv)

Cause and suggested fix

run.sh quotes an unset variable on the launch line:

$JUPYTER --no-browser \
  "$BASE_URL_FLAG" \
  --ServerApp.ip='*' \
  ...

When BASE_URL is empty (the subdomain = true path), BASE_URL_FLAG is never set, so "$BASE_URL_FLAG" expands to an empty "" argument. Unquoting it makes an empty value contribute no argument (the flag value has no whitespace, so this is safe):

$JUPYTER --no-browser \
  $BASE_URL_FLAG \
  --ServerApp.ip='*' \
  ...

Happy to open a PR (patch-level bump).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions