can1357/oh-my-pi · error · Error

[${path}]: ${error.message}\nNo files were modified — sectio

Error message

[${path}]: ${error.message}\nNo files were modified — sections apply atomically.

What it means

When a multi-file section-edit (sloppy edit) fails to apply a section to one file, the tool re-throws it wrapped with the file path and a note that the operation is atomic: no files from the batch were written. The wrapper preserves the original apply error (e.g. section not found, ambiguous match) and adds which file failed.

Source

Thrown at packages/coding-agent/src/edit/sloppy.ts:3959

					if (!isEnoent(strippedError)) throw strippedError;
				}
			}
		}

		enforcePlanModeWrite(session, path);

		const rawContent = await readEditFileText(absolutePath, path);
		const { bom, text: fileText } = stripBom(rawContent);
		const originalEnding = detectLineEnding(fileText);
		const normalizedContent = normalizeToLF(fileText);

		const notes: string[] = [];
		let newContent: string;
		try {
			newContent = applySloppy(normalizedContent, normalizeToLF(section.body), { path, notes });
		} catch (error) {
			if (!(error instanceof Error) || !multiFile) throw error;
			throw new Error(`[${path}]: ${error.message}\nNo files were modified — sections apply atomically.`);
		}
		if (newContent === normalizedContent) {
			throw new Error(`Edits to ${path} resulted in no changes being made.`);
		}
		prepared.push({ path, absolutePath, rawContent, bom, originalEnding, normalizedContent, newContent, notes });
	}

	// Phase 2 — write every prepared section; only the last write flushes the LSP batch.
	const perFileResults: EditToolPerFileResult[] = [];
	const contentTexts: string[] = [];
	let singleResult: EditResult | undefined;
	let firstChangedLine: number | undefined;
	for (let index = 0; index < prepared.length; index++) {
		const entry = prepared[index];
		const isLast = index === prepared.length - 1;
		const sectionBatch: LspBatchRequest | undefined = batchRequest
			? { id: batchRequest.id, flush: isLast && batchRequest.flush }
			: undefined;

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the target file fresh and verify the section heading/body matches exactly
  2. Apply sections one file at a time to identify the failing section
  3. Fix the section body/heading in the tool call to match the current file content
  4. If the section was intentionally unchanged, remove it from the batch

Example fix

// before: section body guessed, no match
edit sections: [{ heading: '## Usage', body: 'stale text' }]
// after: re-read file, copy exact heading/body
const src = await Bun.file(path).text();
edit sections: [{ heading: '## Usage', body: extractCurrentBody(src) }]
Defensive patterns

Strategy: validation

Validate before calling

const src = await Bun.file(path).text();
if (!src.includes(section.heading)) throw new Error(`heading ${section.heading} not in ${path}`);

Type guard

function isSectionPresent(file: string, heading: string): boolean { return file.includes(heading); }

Try / catch

try { await editSections(files) } catch (e) { if (/No files were modified/.test(e.message)) { /* re-read files, fix failing section named in [path] */ } else throw e }

Prevention

When it happens

Trigger: Calling the multi-file section edit tool when applySloppy() throws for a given path — typically because a section heading/body in the requested content does not match the file (or a prior section's edits shifted content). Only thrown when multiFile is true; single-file edits rethrow the raw error.

Common situations: LLM-generated section content that doesn't exactly match an existing heading; stale file content from a previous read; applying sections to multiple files where one file was renamed or restructured; BOM/line-ending mismatch after normalization.

Related errors


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