Incus-simplestreams seems not to use "description" from image

I’m not sure if this is me driving it wrong, or there’s something I don’t understand in the tool.

I’ve created an image with some properties, including “description” set by incus publish ... description=..... I can see it in the image:

$ incus image list
+-----------+--------------+--------+--------------------------------------------+--------------+-----------+-----------+----------------------+
|   ALIAS   | FINGERPRINT  | PUBLIC |                DESCRIPTION                 | ARCHITECTURE |   TYPE    |   SIZE    |     UPLOAD DATE      |
+-----------+--------------+--------+--------------------------------------------+--------------+-----------+-----------+----------------------+
| vtp       | 0693a9739166 | yes    | Virtual Training Platform (20260326_15:45) | x86_64       | CONTAINER | 513.83MiB | 2026/03/26 15:46 UTC |
+-----------+--------------+--------+--------------------------------------------+--------------+-----------+-----------+----------------------+

Then I export the image, and I can see the description has made it through to metadata.yaml:

$ cat metadata.yaml
architecture: x86_64
creation_date: 1774539908
expiry_date: 1776764486
properties:
  architecture: amd64
  description: Virtual Training Platform (20260326_15:45)    <<<< NOTE
  name: ubuntu-noble-amd64-cloud-20260322_09:33              < (Didn't bother to replace this one)
  os: vtp
  release: main
  serial: "20260326_15:45"
  variant: default
templates:
...

Then I import to a webserver using incus-simplestreams add. The problem is that at this point, the description seems to be ignored, and replaced with a generic “{os} {release} {arch} ({time})”

# incus-simplestreams list
+------------------------------------------------------------------+-------------------------------------+-----------+---------+---------+--------------+-----------+----------------------+
|                           FINGERPRINT                            |             DESCRIPTION             |    OS     | RELEASE | VARIANT | ARCHITECTURE |   TYPE    |       CREATED        |
+------------------------------------------------------------------+-------------------------------------+-----------+---------+---------+--------------+-----------+----------------------+
| 0693a9739166917fe643dc99f1dd6e6c6fe383b715dbbd5fac7869e97f7036d6 | vtp main amd64 (202603261545)       | vtp       | main    | default | x86_64       | container | 2026/03/26 00:00 UTC |
+------------------------------------------------------------------+-------------------------------------+-----------+---------+---------+--------------+-----------+-------------

I see the same when I query from a remote client:

$ incus image info nsrc:vtp
...
Properties:
    os: vtp
    release: main
    architecture: amd64
    serial: 202603261545
    description: vtp main amd64 (202603261545)   <<< HERE
    variant: default
    type: tar.gz

(Aside: the serial has also changed from what was originally published)

However, the help text implies that the description property should be used:

# incus-simplestreams add --help
Description:
  Add an image to the server

  This command parses the metadata tarball to retrieve the following fields from its metadata.yaml:
   - architecture
   - creation_date
   - properties["description"]      <<<<< HERE
   - properties["os"]
   - properties["release"]
   - properties["variant"]
   - properties["architecture"]

If I look in streams/v1/{images.json,index.json} I can see neither the original description from the published image, nor the new description.

Is the “description” property synthesized by incus-simplestreams list, and by the client? In which case, is there any point setting it in the image?

I am using incus-simplestreams from incus-extra 1:6.22-ubuntu22.04-202603220542 (Zabbly)

Thanks,

Brian.

So the help message isn’t technically wrong but also not particularly useful :slight_smile:

Our simplestreams implementation is a bit weird because of how things worked with the Ubuntu image server back when we implemented this whole thing in LXD.

Basically, the image servers aren’t expected to provide a full description field and most do not, instead the Incus simplestreams Go client will automatically generate that field based on data from other fields, that’s what you’re seeing in the list output.

BUT, the description field as a property inside of the metadata WILL still make it to the target system as it’s encoded in its metadata.json (inside the metadata tarball) and will turn into an image property on the target system, just not visible on the image server.

So yeah, as mentioned, this is a bit of a mess :slight_smile:
It’s a more fixable mess now that we’re mostly relying on our own public image server and tooling, but still something we’d want to start tweaking with a lot of care so as not to break older versions of Incus and all the various clients out there that may directly interact with our image server.

Therefore it should show when the image is pulled?

I tried adding the simplestreams server as a remote on a different system, and I launched a container from it (thus pulling the image), but the image still shows the default description and serial:

nsrc@vtp-dev:~$ incus image list
+-------+--------------+--------+-------------------------------------+--------------+-----------+-----------+----------------------+
| ALIAS | FINGERPRINT  | PUBLIC |             DESCRIPTION             | ARCHITECTURE |   TYPE    |   SIZE    |     UPLOAD DATE      |
+-------+--------------+--------+-------------------------------------+--------------+-----------+-----------+----------------------+
|       | e42c123b7f2d | no     | vtp-proxy main amd64 (202603261548) | x86_64       | CONTAINER | 231.77MiB | 2026/03/27 09:58 UTC |
+-------+--------------+--------+-------------------------------------+--------------+-----------+-----------+----------------------+
nsrc@vtp-dev:~$ incus image info e42c123b7f2d
Fingerprint: e42c123b7f2d8d2a5a6be97ae2fad425c21058331090f70bdc59733b6f506315
Size: 231.77MiB
Architecture: x86_64
Type: container
Public: no
Timestamps:
    Created: 2026/03/26 00:00 UTC
    Uploaded: 2026/03/27 09:58 UTC
    Expires: 1970/01/01 00:00 UTC
    Last used: 2026/03/27 09:58 UTC
Properties:
    description: vtp-proxy main amd64 (202603261548)  <<<<
    os: vtp-proxy
    release: main
    serial: 202603261548                              <<<<
    type: tar.gz
    variant: default
    architecture: amd64
Aliases:
Cached: yes
Auto update: enabled
Source:
    Server: https://<SNIP>
    Protocol: simplestreams
    Alias: vtp-proxy
Profiles:
    - default

As does the container I launched from this image:

nsrc@vtp-dev:~$ incus config show vtp-proxy
architecture: x86_64
config:
  image.architecture: amd64
  image.description: vtp-proxy main amd64 (202603261548)  <<<<
  image.os: vtp-proxy
  image.release: main
  image.serial: "202603261548"                            <<<<
  image.type: tar.gz
  image.variant: default
  volatile.base_image: e42c123b7f2d8d2a5a6be97ae2fad425c21058331090f70bdc59733b6f506315
  volatile.cloud-init.instance-id: 38706e15-aa3b-499b-87cb-7c7e0e04d748
... snip ...

However, if I look in the metadata.yaml file of the downloaded image, I do see the original description and serial, as you said:

root@vtp-dev:/home/nsrc# tar -tzf /var/lib/incus/images/e42c123b7f2d8d2a5a6be97ae2fad425c21058331090f70bdc59733b6f506315 | head -5
metadata.yaml
rootfs
rootfs/bin
rootfs/bin.usr-is-merged
rootfs/boot
root@vtp-dev:/home/nsrc# tar -xvzf /var/lib/incus/images/e42c123b7f2d8d2a5a6be97ae2fad425c21058331090f70bdc59733b6f506315 metadata.yaml
metadata.yaml
root@vtp-dev:/home/nsrc# cat metadata.yaml
architecture: x86_64
creation_date: 1774540103
expiry_date: 1776764486
properties:
  architecture: amd64
  description: VTP Proxy Front-end (20260326_15:48)  <<<<
  name: ubuntu-noble-amd64-cloud-20260322_09:33
  os: vtp-proxy
  release: main
  serial: "20260326_15:48"                           <<<<
  variant: default
templates:
  /etc/hostname:
... snip ...

If the correct description/serial properties are in the downloaded metadata.yaml file, why are they not being used? My best guess is: “incus image info” isn’t looking in metadata.yaml, it’s looking in the local SQL database; and the local SQL database entry isn’t populated from the downloaded metadata.yaml, it’s populated from streams/v1/images.json. Perhaps that’s to avoid having to unzip/untar the image at download time?

If I look at the same image on the server where the container image was built, I do see the custom description and serial that I set:

nsrc@brian-kit:~$ incus image info e42c123b7f2d
Fingerprint: e42c123b7f2d8d2a5a6be97ae2fad425c21058331090f70bdc59733b6f506315
Size: 231.77MiB
Architecture: x86_64
Type: container
Public: yes
Timestamps:
    Created: 2026/03/26 15:48 UTC
    Uploaded: 2026/03/26 15:48 UTC
    Expires: 2026/04/21 09:41 UTC
    Last used: never
Properties:
    description: VTP Proxy Front-end (20260326_15:48)
    name: ubuntu-noble-amd64-cloud-20260322_09:33    <<<<
    os: vtp-proxy
    release: main
    serial: 20260326_15:48                           <<<<
    variant: default
    architecture: amd64
Aliases:
    - vtp-proxy
Cached: no
Auto update: disabled
Profiles:
    - default
nsrc@brian-kit:~$

Note that it’s exactly the same fingerprint I’m passing to “incus image info” in all cases.

You’d think the job of a cryptographic fingerprint would be to ensure that you see the same data everywhere - but that’s not the case here. Hence I do feel somewhat justified in being confused by this :slight_smile:

EDIT: I note that you can use incus image set-property to change local properties of an existing image, without affecting the hash, so clearly they’re not covered by the hash (even if metadata.yaml is!)

nsrc@vtp-dev:~$ incus image list
+-------+--------------+--------+-------------------------------------+--------------+-----------+-----------+----------------------+
| ALIAS | FINGERPRINT  | PUBLIC |             DESCRIPTION             | ARCHITECTURE |   TYPE    |   SIZE    |     UPLOAD DATE      |
+-------+--------------+--------+-------------------------------------+--------------+-----------+-----------+----------------------+
|       | e42c123b7f2d | no     | vtp-proxy main amd64 (202603261548) | x86_64       | CONTAINER | 231.77MiB | 2026/03/27 09:58 UTC |
+-------+--------------+--------+-------------------------------------+--------------+-----------+-----------+----------------------+
nsrc@vtp-dev:~$ incus image set-property e42c123b7f2d description "VTP Proxy Front-end (20260326_15:48)"
nsrc@vtp-dev:~$ incus image list
+-------+--------------+--------+--------------------------------------+--------------+-----------+-----------+----------------------+
| ALIAS | FINGERPRINT  | PUBLIC |             DESCRIPTION              | ARCHITECTURE |   TYPE    |   SIZE    |     UPLOAD DATE      |
+-------+--------------+--------+--------------------------------------+--------------+-----------+-----------+----------------------+
|       | e42c123b7f2d | no     | VTP Proxy Front-end (20260326_15:48) | x86_64       | CONTAINER | 231.77MiB | 2026/03/27 09:58 UTC |
+-------+--------------+--------+--------------------------------------+--------------+-----------+-----------+----------------------+

FWIW, I came across another oddity with simplestreams. There is a cache, which is sometimes used and sometimes not. As a result, it is possible to see inconsistent results, where incus image info says that an image exists, but incus launch says it doesn’t.

nsrc@vtp-dev:~$ incus image info nsrc:vtp-proxy
Fingerprint: 6421ab83345bd0580a8b46809879c29f791d895521d9f20d0d152a4bc125e445
Size: 231.78MiB
Architecture: x86_64
Type: container
Public: yes
Timestamps:
    Created: 2026/03/27 00:00 UTC
    Uploaded: 2026/03/27 00:00 UTC
    Expires: 1970/01/01 00:00 UTC
    Last used: never
Properties:
    os: vtp-proxy
    release: main
    variant: default
    architecture: amd64
    serial: 202603271319
    description: vtp-proxy main amd64 (202603271319)
    type: tar.gz
Aliases:
    - vtp-proxy/main/default
    - vtp-proxy/main/default/amd64
    - vtp-proxy
    - vtp-proxy/amd64
Cached: no
Auto update: disabled
Profiles: []
nsrc@vtp-dev:~$ incus launch nsrc:vtp-proxy vtp-proxy
Launching vtp-proxy
Error: Failed instance creation: Failed getting remote image info: Failed getting image: The requested image couldn't be found

What happened was I’d previously added the image to incus-simplestreams without an alias, then re-added it with an alias.

Restarting incusd didn’t make a difference. I expect it would have resolved itself eventually, but I ended up working around like this:

rm /var/cache/incus/*/{images.json,index.json}

(Guess: incus image info xxx:img is talking directly to remote xxx:, whereas incus launch xxx:img talks to the current default remote, e.g. yyy:, which in turn uses its cache before talking to xxx:)