Skip to content

wekan

v9.69 Breaking

This release includes breaking changes for platform teams planning a safe upgrade.

Published 1mo Productivity & Wikis
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

docker javascript kanban meteor real-time sandstorm
+2 more
snapcraft wekan

Affected surfaces

auth breaking_upgrade

Summary

AI summary

Updates https://github.com/wekan/wekan/issues/3252, req.body.members, and https://github.com/wekan/wekan/issues/3697 across a mixed release.

Full changelog

v9.69 2026-06-23 WeKan ® release

This release fixes the following bugs:

  • Can't edit a card's members in the UI after removing them via the REST API,
    #3697: clearing a card's members (or assignees) over REST left the
    field uneditable in the UI. The card PUT handler guarded with if (req.body.members) — falsy for the two natural
    clear payloads (null and "") — so "remove the last member" was a silent no-op, and its string branch was written
    to store null rather than []; a card with members: null then breaks UI code that treats it as an array. The
    handler now uses an !== undefined guard plus a shared coercion helper so any clear payload (null / "" / [])
    stores a clean String[] (never null), a single id is wrapped into an array, and stray non-string entries are
    dropped; getMembers()/getAssignees() also coerce a legacy null to [] on read so existing corrupted documents
    edit cleanly. Pure logic in models/lib/restArrayParam.js with a Meteor-free Node unit test
    (tests/restArrayParam.test.cjs, npm run test:unit:node, incl. a negative test reproducing the old
    null-writing logic), plus a REST regression in tests/playwright/specs/17-rest-api.e2e.js.
  • Can't create a card with no member via the REST API,
    #2875: the card-create endpoints (POST .../cards and
    POST .../cards/bulk) wrote req.body.members/assignees straight to the insert with no normalization — the
    create-side twin of #3697 — so a null/"" payload persisted as null (breaking later UI editing). Both handlers
    now run the same coerceRestArrayParam helper: the field is omitted when not provided (so the schema default []
    applies), any clear payload becomes [] (never null), and a single id is wrapped into an array. REST regression in
    tests/playwright/specs/17-rest-api.e2e.js.
  • Board created through the REST API shows in the API but not in the browser UI,
    #5650: POST /api/boards set the board's sole member's userId from
    req.body.owner with no fallback, so a request that omits owner created a board whose only member had
    userId: undefined. The board-list publication matches members.$elemMatch: { userId, isActive: true }, which can
    never match an undefined id — so the board was returned by the REST API but invisible in the browser. owner now
    falls back to the authenticated caller (req.body.owner || req.userId), mirroring the Meteor create method. REST +
    DB regression in tests/playwright/specs/17-rest-api.e2e.js.
  • Copying a card to another board left its comments on the wrong board,
    #5166: CardComments.copy() cloned a comment but only changed its
    cardId, so a card copied to another board produced comments that kept the source board's boardId. Comment
    permission checks key off the comment's boardId, so edit/delete on a copied comment was validated against the wrong
    board, and any board-scoped query saw it on the old board. copy() now also sets the destination boardId (the
    author userId is intentionally preserved). Cross-board copy regression in
    tests/playwright/specs/17-rest-api.e2e.js. Note: the related "wrong author shown" symptom is a separate display
    issue — when a copied comment's author is not a member of the destination board, their user document isn't
    published there, so the UI can't resolve the name; adding those users to the board resolves it. A broader fix
    (publishing comment authors' minimal profile on boards where their comments appear) is left as a follow-up.
  • Exception "Removed nonexistent document" when deleting a card detail,
    #3252 (partial): deleting a comment or checklist/checklist-item could
    throw Removed nonexistent document on the client. The delete handlers called Collection.remove(_id) directly, but
    under heavy archive/delete churn the target doc can already have been evicted from the client's Minimongo cache, and
    removing a missing _id throws. The comment / checklist / checklist-item delete handlers now check the doc still
    exists in the local cache before removing it
    (client/components/activities/comments.js, client/components/cards/checklists.js). The server-side
    before.remove hooks were already hardened to guard + log instead of throwing. (No automated regression for the
    thrown exception — the eviction race is not deterministically reproducible; the guard itself is a self-evident
    findOne-then-remove.) The high CPU on bulk delete the issue also reports is reduced by the cascade change below;
    the remaining cost is on the archive path (a bulk update, not a delete) and is a separate follow-up.
  • Performance: deleting a card no longer fans out per-child activity churn (#3252,
    #5322). cardRemover removed a card's checklist items, checklists and
    comments with the hooked removeAsync, so collection-hooks fired each child's before.remove once per document
    every one doing a getCard and inserting an activity (e.g. a removedChecklistItem per item), which then triggered
    the notification + publication observers. Deleting (or bulk-deleting) a card with many children produced an
    activity-insert storm and pegged the CPU. cardRemover now removes those children with .direct (skipping the
    per-child hooks — they only logged activities that are unviewable once the card is gone) and clears all of the
    card's activities in a single bulk op, which also removes the activities that a delete previously left orphaned. The
    deleteCard activity is still logged afterward (so the outgoing webhook fires), and attachments still go through the
    normal remove so their files are deleted. Cascade + activity-cleanup regression (also a negative test) in
    tests/playwright/specs/17-rest-api.e2e.js.

and this issue is verified resolved in current code (could not reproduce / no error observed here; re-test on the
reporter's data requested):

  • #2292 (archiving a swimlane appeared to delete all its cards):
    Swimlane.archive() (models/swimlanes.js) only sets archived: true on the swimlane — it
    does not touch or delete the cards, and restore() brings the swimlane and its cards back. While a swimlane is
    archived its cards are merely hidden from the board view (board queries filter to archived: false swimlanes), not
    lost — the v2.27-era cascade described in the report no longer happens. (A dedicated way to view an archived
    swimlane's cards before restoring would be a separate UX improvement.)

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track wekan

Get notified when new releases ship.

Sign up free

About wekan

The Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . New English strings for new features at imports/i18n/data/en.i18n.json . Non-English translations at https://app.transifex.com/wekan/wekan only.

All releases →

Related context

Beta — feedback welcome: [email protected]