Tencent/WeKnora · error

extraction model returned no usable output within %d tokens;

Error message

extraction model returned no usable output within %d tokens; if this is a reasoning model, its thinking is consuming the budget

What it means

The extraction model call completed but produced nil output or output flagged as truncated within the retry token budget, so no usable extraction result exists. Commonly a reasoning model whose thinking tokens exhaust the budget before emitting the final answer. Returning the error keeps the watermark in place so messages are retried.

Source

Thrown at internal/application/service/memory/extract.go:983

	}

	// A truncated call is retried once with room to spare. Reasoning models
	// that ignore the disable flag spend the whole budget thinking and return
	// an empty string, which is indistinguishable from "nothing to record"
	// unless the finish reason is checked.
	if isTruncated(response) {
		logger.Warnf(ctx,
			"memory: extraction hit the token ceiling with %d chars of content, retrying with %d tokens",
			len(strings.TrimSpace(response.Content)), extractBudgetRetryTokens)
		response, err = s.completeExtraction(ctx, chatModel, userPrompt, extractBudgetRetryTokens)
		if err != nil {
			return extractionResponse{}, err
		}
		if response == nil || isTruncated(response) {
			// Returning an error is what keeps the watermark where it is, so
			// these messages are read again rather than silently consumed by a
			// run that learned nothing.
			return extractionResponse{}, fmt.Errorf(
				"extraction model returned no usable output within %d tokens; "+
					"if this is a reasoning model, its thinking is consuming the budget",
				extractBudgetRetryTokens)
		}
	}

	parsed, err := parseExtractionResponse(response.Content)
	if err != nil {
		// A malformed but complete response is the model's fault, not a
		// transient failure: the same prompt at temperature zero produces the
		// same garbage, so retrying only burns the budget. Truncation is
		// handled above precisely because it is *not* this case.
		logger.Warnf(ctx, "memory: unparsable extraction response: %v", err)
		return extractionResponse{}, nil
	}
	return parsed, nil
}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Switch the workspace memory extraction model to a non-reasoning chat model
  2. Increase the extraction token budget in workspace memory settings
  3. Shorten the input message batch so the output fits the budget
  4. Check the wrapped response's finish_reason to confirm truncation before tuning

Example fix

// before
// reasoning model with default budget
"memory.extractionModel": "deepseek-r1"
// after
"memory.extractionModel": "claude-3-5-sonnet" // non-reasoning model that emits output within budget
Defensive patterns

Strategy: fallback

Validate before calling

// prefer non-reasoning models for extraction, or raise the budget
if isReasoningModel(modelID) {
	budget = reasoningModelBudget // larger token budget
}

Try / catch

_, err := memorySvc.Handle(ctx, run)
if err != nil && strings.Contains(err.Error(), "no usable output within") {
	// switch extraction model or increase budget, then re-run;
	// the watermark is intact so messages will be re-read
	return ErrExtractionBudgetExhausted
}

Prevention

When it happens

Trigger: callExtractionModel invoked with a small extractBudgetRetryTokens budget against a model that returns nil or a truncated response (finish_reason=length).

Common situations: Switching the memory extraction model to a reasoning model (o1/deepseek-r1 style) whose hidden thinking consumes the token budget; budget configured too low for long message batches; provider returning truncated responses under load.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/102e11eca49747b3. Report an issue: GitHub.