wslc: containers do not inherit image labels (Config.Labels missing), silently breaking VS Code Dev Containers Feature lifecycle hooks
@beena352 is already working on this.
Since Aug 3, 2026.
- Dominant language
- C++
- Stars
- 33.7k
- Forks
- 1.8k
- Avg merge
- 3d 17h
- Merged PRs (30d)
- 116
Description
### Windows Version
Microsoft Windows [Version 10.0.26200.8893]
### WSL Version
2.9.4.0
### Are you using WSL 1 or WSL 2?
- [X] WSL 2
- [ ] WSL 1
### Kernel Version
6.18.35.2-1
### Distro Version
Ubuntu 24.04
### Other Software
- wslc 2.9.4.0 (`wslc version`)
- VS Code 1.130.0, Dev Containers extension 0.467.0 (affected downstream)
- `@devcontainers/cli` 0.88.0
- For comparison: Docker Engine (any recent version) exhibits the expected behavior
### Repro Steps
The repro is independent of VS Code / Dev Containers — three commands from a WSL distro (or the Windows side, with `wslc.exe`):
```sh
printf 'FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04\nLABEL test.label="hello-from-image"\n' > Dockerfile
wslc build -t label-test .
wslc run -d --name label-test-c label-test sleep infinity
# Image inspect: label is present
wslc inspect --type image label-test # -> Config.Labels contains "test.label": "hello-from-image"
# Container inspect: label is gone
wslc inspect label-test-c # -> Config.Labels is absent entirely
```
Cleanup: `wslc rm -f label-test-c; wslc rmi label-test`
### Expected Behavior
Containers created from an image inherit the image's labels, as with Docker Engine. `docker inspect ` shows `Config.Labels` populated with the image's labels merged with any `--label` flags (user-provided labels win on conflict).
References:
- Dockerfile reference (`LABEL`): "Labels included in base images (images in the `FROM` line) are inherited by your image." — https://docs.docker.com/reference/dockerfile/#label
- Docker Engine implementation: at container create, the daemon merges the image config into the container config, including labels — `mergeAndVerifyConfig` in [`daemon/create.go`](https://github.com/moby/moby/blob/master/daemon/create.go) calling `merge()` ([`daemon/commit.go`](https://github.com/moby/moby/blob/master/daemon/commit.go), the `imageConf.Labels` loop).
Expected `wslc inspect label-test-c` (excerpt):
```json
"Config": {
"Labels": {
"test.label": "hello-from-image",
"...": "(labels inherited from the base image)"
}
}
```
### Actual Behavior
`wslc inspect ` returns a `Config` object with **no `Labels` key at all** (observed keys: `Cmd`, `Entrypoint`, `Env`, `Healthcheck`, `StopTimeout`, `User`, `WorkingDir`). The top-level `Labels` field contains only labels passed explicitly via `--label` at `run`/`create` time. Image labels are never propagated to the container.
`wslc inspect --type image` does show the labels correctly, so the metadata survives `wslc build`; it is only the image-to-container inheritance step that is missing.
#### Real-world impact: VS Code Dev Containers silently loses Feature lifecycle hooks
The Dev Containers spec stores merged Feature metadata (including `onCreateCommand` / `postCreateCommand` contributed by Features) as a `devcontainer.metadata` **image label**, which tooling later reads back **from the container**:
- containers.dev spec: "The metadata is added to the image as a `devcontainer.metadata` label with a JSON string value" and it is "merged with any local devcontainer.json file contents at the time the container is created" — https://containers.dev/implementors/spec/#image-metadata
- `@devcontainers/cli` reads it via `containerDetails.Config.Labels['devcontainer.metadata']` and falls back to *empty metadata* when the label is absent — [`src/spec-node/imageMetadata.ts`, `getImageMetadataFromContainer`](https://github.com/devcontainers/cli/blob/main/src/spec-node/imageMetadata.ts)
The VS Code Dev Containers extension runs `devcontainer up --skip-post-create` and then executes lifecycle hooks in a separate `run-user-commands` phase that resolves hooks from the container's `devcontainer.metadata` label. With wslc, the label is invisible on the container, so all Feature-contributed lifecycle commands are **silently skipped** — no error, the container just comes up missing everything a Feature's `onCreateCommand` was supposed to install. I hit this in practice with a Nix devcontainer Feature: the container started, but `nix`/`direnv` were absent because `onCreateCommand` never ran; the marker files were written but no command executed.
This makes any devcontainer Feature that relies on lifecycle hooks (most non-trivial ones) unusable with wslc when opened through VS Code, in a way that is very hard for users to diagnose.
Note that wslc support was deliberately added to the Dev Containers tooling recently (`@devcontainers/cli` 0.88.0, [devcontainers/cli#1249](https://github.com/devcontainers/cli/pull/1249); Dev Containers extension 0.462.0+). That work adapts to several wslc differences (e.g. no `events` command → polling fallback, `--mount` → volume-arg conversion), but the Features metadata path still assumes Docker's image-label inheritance, so this incompatibility remains unhandled on the tooling side. I found no statement in the VS Code Dev Containers documentation, the WSL container documentation ([wsl-container](https://learn.microsoft.com/en-us/windows/wsl/wsl-container), [containers tutorial](https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-containers)), or either project's changelog declaring label inheritance (or Feature lifecycle hooks) as a known limitation.
Prior-issue search: I reviewed the wslc-related issues in this repo (~50, e.g. #14432 volume-flag differences, #40957 bind mounts, #41123 image store) and in microsoft/vscode-remote-release (#11694 tracking, #11750, #11725, #11723) and devcontainers/cli — no existing report of missing image-label inheritance.
### Diagnostic Logs
_No response_
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.