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
- Confirm the card id exists: Cards.findOne(cardId) on a subscribed client before calling.
- Re-subscribe to the board to refresh deleted/archived card state.
- Fix the caller passing the wrong id type.
- 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
- Derive card ids from the reactive subscription, not from long-lived component state.
- Listen for card-removal publications and purge local references immediately.
- Validate id kind in drag payloads (card vs list vs swimlane).
- Skip tracking for cards already flagged archived/deleted locally.
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.