wekan/wekan · error · Meteor.Error

card-not-found

card-not-found

Error message

Card not found

What it means

The 'positionHistory.trackCard' method fetches the card with Cards.findOneAsync(cardId) after the login check. When no card matches, it throws 'card-not-found' with message 'Card not found'. It indicates the supplied cardId does not correspond to any document in the Cards collection.

Source

Thrown at server/methods/positionHistory.js:71

      throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
    }

    return list.trackOriginalPosition();
  },

  /**
   * Track original position for a card
   */
  async 'positionHistory.trackCard'(cardId) {
    check(cardId, String);

    if (!this.userId) {
      throw new Meteor.Error('not-authorized', 'You must be logged in.');
    }

    const card = await Cards.findOneAsync(cardId);
    if (!card) {
      throw new Meteor.Error('card-not-found', 'Card not found');
    }

    const board = await ReactiveCache.getBoard(card.boardId);
    if (!board || !board.isVisibleBy({ _id: this.userId })) {
      throw new Meteor.Error('not-authorized', 'You do not have access to this board.');
    }

    return card.trackOriginalPosition();
  },

  /**
   * Get original position for a swimlane
   */
  async 'positionHistory.getSwimlaneOriginalPosition'(swimlaneId) {
    check(swimlaneId, String);

    if (!this.userId) {
      throw new Meteor.Error('not-authorized', 'You must be logged in.');

View on GitHub (pinned to eb1433158b)

Solutions

  1. Confirm the card id exists: Cards.findOne(cardId) on a subscribed client before calling.
  2. Re-subscribe to the board to refresh deleted/archived card state.
  3. Fix the caller passing the wrong id type.
  4. Catch 'card-not-found' and skip tracking, cleaning up the stale client reference.

Example fix

// before
Meteor.call('positionHistory.trackCard', droppedCardId);

// after
if (Cards.findOne(droppedCardId)) {
  Meteor.call('positionHistory.trackCard', droppedCardId);
} else {
  removeStaleReference(droppedCardId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!Cards.findOne(cardId)) { cleanupStaleCard(cardId); return; }
Meteor.call('positionHistory.trackCard', cardId);

Type guard

function isExistingCard(cardId) {
  return typeof cardId === 'string' && !!Cards.findOne(cardId);
}

Try / catch

try {
  await Meteor.callAsync('positionHistory.trackCard', cardId);
} catch (e) {
  if (e && e.error === 'card-not-found') {
    cleanupStaleCard(cardId); // deleted elsewhere, drop reference
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Meteor.call('positionHistory.trackCard', cardId) with an id of a card that was archived-and-deleted, a mis-keyed id (list or swimlane id passed in), or an id fabricated in a test/script against a different database.

Common situations: Optimistic UI dropping a card whose server document was deleted by another user; stale search results or links pointing at removed cards; copy-pasted ids between environments.

Related errors


AI-assisted analysis of wekan/wekan@eb1433158b (2026-09-01). Data as JSON: /api/errors/a5cb3e61cc41c340. Report an issue: GitHub.