can1357/oh-my-pi · error · Error

Missing map observation for ${files[index]?.filename ?? "unk

Error message

Missing map observation for ${files[index]?.filename ?? "unknown"}

What it means

After the parallel map phase completes, observations are collected per file index. If an LLM result arrives without an observation (model produced no usable per-file summary), the final mapping step throws rather than silently returning a sparse array. Raised by mapPhase.

Source

Thrown at packages/coding-agent/src/commit/conventional/map-reduce.ts:135

		};
	}
	const results = await mapWithConcurrency(batches, MAP_PHASE_CONCURRENCY, async (batch, batchIndex) => {
		const batchFiles = batch.map(index => files[index]).filter(value => value !== undefined);
		const mapped = await mapFileBatch(
			batchFiles,
			headers.headerForFiles(batchFiles.map(file => file.filename)),
			inference,
			`Mapping batch ${batchIndex + 1}/${batches.length} (${batchFiles.length} files)…`,
			budget,
		);
		return batch.map((fileIndex, index) => ({ fileIndex, observation: mapped[index] }));
	});
	for (const batch of results) {
		for (const item of batch) if (item.observation) observations[item.fileIndex] = item.observation;
	}
	return observations.map((observation, index) => {
		if (observation) return observation;
		throw new Error(`Missing map observation for ${files[index]?.filename ?? "unknown"}`);
	});
}

async function mapFileBatch(
	files: readonly ConventionalFileDiff[],
	contextHeader: string,
	inference: CommitInference,
	progressLabel: string,
	budget: number,
): Promise<ConventionalFileObservation[]> {
	const promptFiles = files.map(file => ({ path: file.filename, diff: renderFileDiffForBatch(file, budget) }));
	const prompts = renderConventionalPrompt("map", { files: promptFiles, context_header: contextHeader });
	return inference.complete(
		{
			operation: "map-reduce/map",
			role: "map",
			promptFamily: "map",
			systemPrompt: prompts.system,

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry the map phase; partial LLM failures are usually transient
  2. Reduce batch size (files per LLM call) so the model reliably summarizes each file
  3. Use a stronger/larger model for the map phase
  4. Inspect the map prompt/output extraction for contract mismatches after model changes

Example fix

// before: one missing observation aborts everything
const observations = await mapPhase(files, inference, config);
// after: retry once on failure
let observations;
try {
  observations = await mapPhase(files, inference, config);
} catch {
  observations = await mapPhase(files, inference, config);
}
Defensive patterns

Strategy: retry

Validate before calling

const batches = await collectMapResults();
const missing = batches.filter((b) => !b.observation);
if (missing.length > 0) { /* re-run map for missing indices */ }

Try / catch

try {
  observations = await mapPhase(files, inference, config);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Missing map observation")) {
    observations = await mapPhase(files, inference, config); // retry
  } else throw err;
}

Prevention

When it happens

Trigger: Calling mapPhase (or its callers like observations) when one or more per-file batch LLM calls returned a result whose observation field is empty/undefined — e.g. empty model output, parse failure in the map prompt contract, or a batch item dropped due to an abort/skip.

Common situations: Large batches where the model hits token limits and omits some file summaries, provider returning empty content for some calls, malformed map output that fails lenient extraction, or an aborted signal causing partial results.

Related errors


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