Update Design Block from Selection nests a new group around the existing linked group instead of extending it, and stores the nest inside the library

Application: KiCad x86_64 on x86_64
Version: 10.0.5-10.0.5~ubuntu24.04.1, release build
Libraries:
    wxWidgets 3.2.4 GLX
    FreeType 2.13.2
    HarfBuzz 8.3.0
    FontConfig 2.15.0
    libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3 brotli/1.1.0 zstd/1.5.5 libidn2/2.3.7 libpsl/0.21.2 (+libidn2/2.3.7) libssh/0.10.6/openssl/zlib nghttp2/1.59.0 librtmp/2.3 OpenLDAP/2.6.10
Platform: Linux Mint 22.3, 64 bit, Little endian, wxGTK, X11, x11, X-Cinnamon, cinnamon
OpenGL: NVIDIA Corporation, NVIDIA GeForce RTX 3090/PCIe/SSE2, 4.6.0 NVIDIA 595.84, GLX 1.4
Build Info:
    Date: Jul 24 2026 10:17:46
    wxWidgets: 3.2.4 (wchar_t,wx containers) GTK+ 3.24
    Boost: 1.83.0
    OCC: 7.6.3
    Curl: 8.5.0
    ngspice: 42
    Compiler: GCC 13.3.0 with C++ ABI 1018
    KICAD_IPC_API=ON
    KICAD_USE_PCH=OFF
Locale: 
    Lang: en_AU
    Enc: UTF-8
    Num: 1,234.5
    Encoded кΩ丈: D0BACEA9E4B888 (sys), D0BACEA9E4B888 (utf8)

Description

Update Design Block from Selection in the PCB editor does two things: it writes the selection into the design block's stored layout, and it creates a new group around the selection, linked to that block. When the selection already contains a group linked to the same block, the new group is created around the existing one rather than replacing or extending it.

Repeating the command therefore builds a chain of nested groups, all with the same name and the same lib_id, each one containing the last. The board accumulates one group outline per invocation, and the block's stored .kicad_pcb accumulates the inner groups, so the saved design block ends up containing groups whose lib_id points at that same design block. Every instance later placed from the block inherits the nest.

Nothing reports this. ERC and DRC are unaffected, because none of it is electrically wrong.

Expected: one linked group per placed instance. Updating a block from a selection that already contains that block's linked group should extend or replace that group, not wrap it. The stored block should never contain a group referencing itself.

The boundary condition, which is the useful part

The bug does not fire in every case, and the case where it does not fire suggests where the fix belongs:

Selection passed to Update Design Block from Selection Result
Exactly one group already linked to the block Correct. Updated in place. No new group on the board; the stored block contains zero groups
That same linked group plus any loose object (a track, a via, a text item) Bug. A new group is created wrapping the old one, and the stored block gains the inner group

So the code already recognises "the selection is precisely this block's linked group". It does not recognise "the selection is a superset of this block's linked group", which is exactly what a selection built up over several passes looks like. Building the selection in passes is a natural workflow on a dense board, where dragging one box around eight footprints without catching the ground pours underneath them is impractical.

Steps to reproduce

Two passes are enough to show it. On any board with a few routed footprints, and a design block library you can write to:

  1. Select two or three footprints and the tracks between them. Right-click the block in the Design Blocks panel and choose Update Design Block from Selection. A group appears around the selection, linked to the block. This is correct.
  2. Select that group, and add one more object to the selection, for example a single track that was not in step 1. Run Update Design Block from Selection again.
  3. Observe: a second group outline is now drawn around the first. Save, and inspect the .kicad_pcb: there are two (group ...) entries with the same name and the same lib_id, and the outer one lists the inner one's UUID as a member.
  4. Inspect the library's stored block, <library>.kicad_blocks/<block>.kicad_block/<block>.kicad_pcb. It now contains a (group ...) whose lib_id names the block you are looking at.
  5. Repeat step 2 as many times as you like. Each run adds one more level.

Control case, worth running to confirm the boundary: select the outermost group on its own, with nothing else, and run the command once. It updates in place, adds no new group, and the stored block comes back containing no groups at all.

Evidence from a real board

Built on a two-layer board where the captured stage is 8 footprints, 109 track segments, 9 vias, 4 silkscreen texts and 2 zones, 132 objects in all. The selection was assembled over eight passes, with the command run at the end of each pass. The board was left holding eight groups in one chain:

b6b46702   2 members =  1 object  + 1 group    <- outermost, created by the 8th run
 5a62ed49  28 members = 27 objects + 1 group
  d7e15256  7 members =  6 objects + 1 group
   851a9193 14 members = 13 objects + 1 group
    6c061967 20 members = 19 objects + 1 group
     9fd53356 31 members = 30 objects + 1 group
      4a487332  3 members =  2 objects + 1 group
       7daa6d74 34 members = 34 objects + 0 group   <- innermost, created by the 1st run

Every one of the eight is identical in name and lib_id:

(group "DRV8833-Stage"
    (uuid "4a487332-2f71-4565-a250-cdc6b5d16e6e")
    (lib_id "klp5e-ch09-blocks:DRV8833-Stage")
    (members "5879b70c-3f18-4ccb-ad0b-dddd96c5a846" "7daa6d74-15b0-4c5a-b299-2e1c260dedaf"
        "f23812e3-8a76-4a62-bb89-2f047221f42c"
    )
)

The stored block, klp5e-ch09-blocks.kicad_blocks/DRV8833-Stage.kicad_block/DRV8833-Stage.kicad_pcb, carried seven of those groups, all of them with lib_id "klp5e-ch09-blocks:DRV8833-Stage", which is the block's own identity.

Two further observations that may help narrow it:

  1. The object content is correct throughout. The nested and the clean captures hold identical objects: the same 8 footprints, 109 segments, 9 vias, 2 zones and 6 text items. Only the group structure differs. So the selection is being serialised correctly and only the grouping is wrong.
  2. The schematic half is untouched by the layout update. <block>.kicad_sch and <block>.json were byte-for-byte identical before and after, and after a second update as well. The bug is confined to the layout half's group handling.

Recovery, for anyone who hits this before it is fixed. Rewrite the board so that a single group holds every leaf member of the chain, keeping the outermost group's UUID, then run Update Design Block from Selection once against that single group. The stored block then comes back with no groups in it. Object counts and DRC were identical before and after doing this, so nothing but the grouping moves. Ungrouping N times in the GUI also works, but it discards a selection that may have taken a long time to build.

Screenshot_from_2026-08-27_14-15-13