can1357/oh-my-pi · error · Error

Lesson was empty after sanitization; nothing stored.

Error message

Lesson was empty after sanitization; nothing stored.

What it means

With memory.backend === "local", learn saves the lesson via localBackend.save(), which sanitizes the content before appending to learned.md and reports how many items were stored. If save returns nothing or stored === 0, the lesson text was stripped to nothing by sanitization, so nothing was persisted and the tool throws this Error to avoid a false success.

Source

Thrown at packages/coding-agent/src/tools/learn.ts:87

				scope: "bank",
				extract: true,
				extractEntities: true,
				veracity: "tool",
				memoryType: "fact",
			});
			// rememberScoped returns undefined when the retain failed (closed DB /
			// disk error); mirror mnemopiBackend.save and fail loudly rather than
			// reporting (and minting a skill for) a lesson that was silently dropped.
			if (!id) {
				throw new Error("Mnemopi did not store the lesson (no memory id returned).");
			}
		} else if (backend === "local") {
			const result = await localBackend.save?.(
				{ agentDir: this.session.settings.getAgentDir(), cwd: this.session.settings.getCwd() },
				{ content: params.memory, context: params.context, source: "coding-agent-learn", importance: 0.8 },
			);
			if (!result || result.stored === 0) {
				throw new Error("Lesson was empty after sanitization; nothing stored.");
			}
		} else {
			const state = this.session.getHindsightSessionState?.();
			if (!state) {
				throw new Error("Hindsight backend is not initialised for this session.");
			}
			state.enqueueRetain(params.memory, params.context);
			memoryMessage = "Lesson queued for retention";
		}

		// 2) Optionally mint/enhance a managed skill. A failure here is surfaced
		// as a partial outcome — the lesson is already stored or queued.
		if (params.skill) {
			// A managed skill resolves below any authored skill of the same name, so
			// minting one under a claimed name writes a file that never surfaces. The
			// lesson is already stored/queued; refuse the skill rather than report a
			// false "Created" (mirrors ManageSkillTool).
			let safeSkillName: string | undefined;

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-call the learn tool with a non-empty, self-contained lesson in params.memory.
  2. Check that the memory argument is not just whitespace or placeholder text.
  3. If the sanitizer is over-aggressive for legitimate content, review the local-backend sanitization rules.

Example fix

// before: memory is only whitespace, sanitizer stores 0 items
{ "memory": "   \n\t  " }
// after: provide an actual lesson
{ "memory": "Always run bun check before committing TypeScript changes." }
Defensive patterns

Strategy: validation

Validate before calling

const memory = params.memory?.trim();
if (!memory) {
  throw new Error("learn requires a non-empty lesson string.");
}

Type guard

function isNonEmptyLesson(s: unknown): s is string {
  return typeof s === "string" && s.trim().length > 0;
}

Try / catch

try {
  await learnTool.execute(id, params);
} catch (err) {
  if (err instanceof Error && err.message.includes("empty after sanitization")) {
    // re-issue the call with real lesson text
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Calling the learn tool with the local backend when params.memory consists only of content the sanitizer removes — e.g. whitespace, control characters, or otherwise empty/invalid text after normalization.

Common situations: The model calls learn with an effectively empty memory string (only whitespace/newlines) or with content that sanitization reduces to an empty string.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/cd951ae6d500c5fb. Report an issue: GitHub.