Skip to content

Cannot create new subpage in group #51

Closed

Description

@maresac

I am trying to create a 2nd level page in my group, which is failing with the following error message popup:
Couldn't create document

Creating documents on the top level or on sublevels of the 2nd level group page works without a problem.

My role is editor; However as owner it also does not succeed and fails with the same error message.

Activity

  1. changed the title [-]Cannot create new subpage[/-] [+]Cannot create new subpage in group[/+] on Oct 27, 2026
  2. christianhuening commented on Oct 28, 2026

    @christianhuening
    Contributor

    I found the cause. It's a bug in how 0.8.x generates the order key when a new page is placed first under a parent. Once a parent has had seven pages created that way, the next generated key is one that already exists, so every later create under that parent fails. It's already fixed on main, which ships as 0.9.0. I assumed the reporter runs 0.8.1, since 0.9.0 isn't released yet.

    What happens (v0.8.1)

    • When you click "+" on a page, the web app sends POST /api/docs with a parent_id and no after_id. The server then gives the new page a key just below the first existing subpage: sort_key_between(None, first_sibling), which calls decrement() in crates/knot-storage/src/lexorank.rs at v0.8.1.
    • decrement() breaks once the keys reach "0": for "0" it returns "0m", which sorts after "0". Running the 0.8.1 code for repeated "new subpage" clicks under one parent gives:
      1 m   2 b   3 5   4 2   5 1   6 0   7 0m   8 0m  ← collision
      
    • The 8th create produces "0m" again. That breaks the UNIQUE (workspace_id, parent_id, sort_key) constraint, and the server returns 409 doc.sort_key_conflict. The web app turns any error into the generic "Couldn't create document" toast (DocTree.tsx:113). From then on, every create under that parent fails the same way, because the first sibling is still "0". Archived subpages keep their keys, so archiving pages doesn't help.

    Why it matches the report

    • Role doesn't matter: it's a key collision, not a permission check.
    • Top level works: the old unique constraint treated NULL parents as distinct, so duplicate keys at the top level were silently accepted.
    • Deeper levels work: those groups just haven't had seven pages inserted at the top yet.
    • Only one parent is affected: the busy top-level page whose subpages are the "2nd level" the reporter means. A smaller earlier sign: the 7th page created there appeared second, not first.

    How to confirm on their instance

    • In the browser's network tab, the failing POST /api/docs should return 409 with doc.sort_key_conflict.
    • Or run this query, expecting to see both 0 and 0m:
      SELECT sort_key, title, archived_at FROM documents
      WHERE parent_id = '<id of the top-level page>' ORDER BY sort_key COLLATE "C";

    Fix

    0.9.0 already fixes this (from #52):

    • The 20261024120000_heal_sort_keys migration rewrites the keys of any group containing an invalid key like "0".
    • The new key code rejects "0" as a neighbour, and placement::place then rewrites the group's keys and tries again.
    • placement_rebalances_invalid_neighbours in crates/knot-storage/tests/placement.rs tests the "0" case directly.

    Upgrading should resolve it. Until then, the reporter can create the page somewhere else (for example at the top level) and drag it under the parent, because a move computes its key differently. Moving the page whose key is "0" further down also unblocks creates for a while, but the same problem comes back after a few more pages.

  3. christianhuening commented on Oct 29, 2026

    @christianhuening
    Contributor

    @maresac please check whether the issue is still open for you. knot 0.9.0 should've fixed that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions