TencentCloud/TencentDB-Agent-Memory · warning
[context-offload] build L3 report failed: ${reportErr}
Error message
[context-offload] build L3 report failed: ${reportErr} What it means
Inside the after_tool_call hook, after compaction completes, the plugin builds an L3 trigger report (token accounting) and hands it to reportL3Trigger for upload to the backend /store. The report construction/upload kick-off is wrapped in try/catch so a reporting failure never disrupts the agent loop; it is logged as this warning. The message interpolates the underlying error, e.g. a TypeError from a missing stateManager field or an exception thrown by buildL3TriggerReport.
Source
Thrown at MemoryCore/src/offload/hooks/after-tool-call.ts:339
event,
contextWindow: _contextWindow,
mildThreshold: _mildThreshold,
aggressiveThreshold: _aggressiveThreshold,
tokensBefore: _tokensBefore,
tokensAfter: _tokensAfter,
messagesBefore: _msgsBefore,
messagesAfter: _msgsAfter,
durationMs: _compDuration,
aboveMild: _tokensBefore >= _mildThreshold,
aboveAggressive: _tokensBefore >= _aggressiveThreshold,
mildReplacedCount: _compResult.mildReplacedCount ?? 0,
aggressiveDeletedCount: _compResult.aggressiveDeletedCount ?? 0,
emergencyTriggered: _compResult.emergencyTriggered ?? false,
emergencyDeletedCount: _compResult.emergencyDeletedCount ?? 0,
});
reportL3Trigger(backendClient ?? null, report, logger);
} catch (reportErr) {
logger.warn(`[context-offload] build L3 report failed: ${reportErr}`);
}
}
// Trace full messages snapshot at end of after_tool_call
if (event.messages && Array.isArray(event.messages)) {
traceMessagesSnapshot({
sessionKey: stateManager.getLastSessionKey(),
stage: "after_tool_call.end",
messages: event.messages,
label: `tool=${event.toolName}`,
extra: {
toolName: event.toolName,
toolCallId,
pendingCount: stateManager.getPendingCount(),
activeMmdFile: stateManager.getActiveMmdFile() ?? null,
l15Settled: stateManager.l15Settled,
},
logger,View on GitHub (pinned to 3efcd317b8)
Solutions
- Read the interpolated reportErr in the log — it names the exact property or call that failed.
- Verify the compaction result shape matches what buildL3TriggerReport expects (upgrade/downgrade plugin and server to matching versions).
- Confirm stateManager was initialized for this session (no undefined snapshot fields).
- If a custom backendClient is passed, ensure reportL3Trigger-compatible methods do not throw synchronously.
- This only affects telemetry/token accounting, not compaction itself — the conversation continues normally; fix at leisure.
Example fix
// before: report build crashes on missing compaction detail
mildReplacedCount: _compResult.mildReplacedCount ?? 0,
aggressiveDeletedCount: _compResult.aggressiveDeletedCount ?? 0,
// after: harden the whole compaction-derived report input against null
const comp = _compResult ?? {};
// ...
mildReplacedCount: comp.mildReplacedCount ?? 0,
aggressiveDeletedCount: comp.aggressiveDeletedCount ?? 0,
emergencyTriggered: comp.emergencyTriggered ?? false, Defensive patterns
Strategy: type-guard
Validate before calling
const comp = _compResult ?? {};
const safeReportInput = {
mildReplacedCount: typeof comp.mildReplacedCount === "number" ? comp.mildReplacedCount : 0,
aggressiveDeletedCount: typeof comp.aggressiveDeletedCount === "number" ? comp.aggressiveDeletedCount : 0,
emergencyTriggered: comp.emergencyTriggered === true,
emergencyDeletedCount: typeof comp.emergencyDeletedCount === "number" ? comp.emergencyDeletedCount : 0,
}; Type guard
function isReportableCompaction(c: unknown): c is CompactionResult {
return c !== null && typeof c === "object" &&
("mildReplacedCount" in c || "aggressiveDeletedCount" in c);
} Try / catch
try {
const report = buildL3TriggerReport({ /* normalized inputs */ });
reportL3Trigger(backendClient ?? null, report, logger);
} catch (reportErr) {
logger.warn(`[context-offload] build L3 report failed: ${reportErr}`);
// telemetry only — do not rethrow
} Prevention
- Normalize the compaction result (default every optional field) before building the report.
- Keep plugin and server versions aligned so CompactionResult shapes match.
- Wrap all telemetry-building code in its own try/catch, separate from compaction logic.
- If the log recurs, capture reportErr.stack to pinpoint the undefined field quickly.
When it happens
Trigger: buildL3TriggerReport(...) throws while assembling the report — typically when _compResult or stateManager fields are undefined/null in a shape the code does not expect (e.g. a compaction result missing mildReplacedCount internals accessed beyond the ?? defaults), or when reportL3Trigger throws synchronously on a malformed backendClient; the backendClient ?? null guard covers null but not a client whose methods throw.
Common situations: Partial compaction results after a server error returned a degraded payload; plugin version mismatch where CompactionResult gained/lost fields; custom backendClient implementations that throw synchronously; corrupt in-memory stateManager state after a hot plugin reload.
AI-assisted analysis of TencentCloud/TencentDB-Agent-Memory@3efcd317b8 (2026-09-01).
Data as JSON: /api/errors/45580dc62851f3c7.
Report an issue: GitHub.