mastra-ai/mastra · error · TripWire

TokenLimiterProcessor: No messages fit within the remaining

Error message

TokenLimiterProcessor: No messages fit within the remaining token budget. Cannot send LLM a request with no messages.

What it means

After keeping all system messages, TokenLimiterProcessor runs best-fit selection over non-system messages against the remaining budget (remainingBudget = limit - systemTokens - conversation overhead). If not even one non-system message fits, the resulting request would contain no conversational messages, so the processor throws a TripWire with retry:false.

Source

Thrown at packages/core/src/processors/processors/token-limiter.ts:206

    for (let i = messages.length - 1; i >= 0; i--) {
      const message = messages[i];
      if (!message) continue;

      const messageTokens = await this.countInputMessageTokens(message);

      if (currentTokens + messageTokens <= remainingBudget) {
        messagesToKeep.unshift(message);
        currentTokens += messageTokens;
      } else {
        if (this.trimMode === 'contiguous') {
          break;
        }
        // best-fit → continue (existing behavior)
      }
    }

    if (messagesToKeep.length === 0) {
      throw new TripWire(
        'TokenLimiterProcessor: No messages fit within the remaining token budget. Cannot send LLM a request with no messages.',
        {
          retry: false,
          metadata: { systemTokens, limit, remainingBudget, messageCount: messages.length },
        },
      );
    }

    // Remove messages that don't fit within the token budget
    const keepIds = new Set(messagesToKeep.map(m => m.id));
    const idsToRemove = messages.filter(m => !keepIds.has(m.id)).map(m => m.id);
    if (idsToRemove.length > 0) {
      messageList.removeByIds(idsToRemove);
    }
  }

  /**
   * Count tokens for a system message. Accepts both untagged and tagged system messages

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Raise maxTokens so the remaining budget after system messages fits at least the latest user message.
  2. Split or truncate very large user messages before they reach the processor.
  3. Reduce system prompt size to increase remainingBudget.
  4. Catch the TripWire and implement application-level truncation/chunking of the input before retrying.

Example fix

// before
new TokenLimiterProcessor({ maxTokens: 2000 }); // remainingBudget < any single message
// after
new TokenLimiterProcessor({ maxTokens: 16000 });
Defensive patterns

Strategy: validation

Validate before calling

const largestMsgTokens = Math.max(...nonSystemMessages.map(m => processor.countTokens(String(m.content))));
const remainingBudget = maxTokens - systemTokens - 1000;
if (remainingBudget < largestMsgTokens) {
  throw new Error('Remaining token budget cannot fit any single message; raise maxTokens or truncate input');
}

Try / catch

try {
  await agent.generate(input);
} catch (e) {
  if (e?.name === 'TripWire' && e?.message?.includes('No messages fit')) {
    // truncate/chunk the newest user message, then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: processInputStep: messagesToKeep.length === 0 after best-fit selection because remainingBudget is smaller than the token count of every candidate message (metadata includes systemTokens, limit, remainingBudget, messageCount).

Common situations: A maxTokens barely above the system prompt size; one enormous user message (e.g. a pasted document) that alone exceeds the budget; a long conversation where the newest message alone doesn't fit.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/a5fb60dac5765767. Report an issue: GitHub.