Yeachan-Heo/oh-my-codex · error · Error

Native hook transaction wrote invalid hooks.json: ${validati

Error message

Native hook transaction wrote invalid hooks.json: ${validation.error.message}

What it means

After a native hook transaction writes hooks.json to disk, setup re-reads the bytes and runs strict validation against the expected Codex hooks schema. If the written file does not conform, the transaction aborts with this error, indicating the write path produced content that would break Codex hook loading. It protects against corruption, partial writes, or bad hook generation.

Source

Thrown at src/cli/setup.ts:1776

async function verifyNativeHookTransactionArtifact(
	applied: AppliedNativeHookTransactionArtifact,
): Promise<void> {
	const { artifact } = applied;
	injectNativeHookTransactionFailure("before_readback", artifact);
	const actual = await captureNativeHookTransactionArtifact(artifact.path, artifact.label);
	if (!nativeHookTransactionSnapshotsEqual(actual, applied.appliedSnapshot)) {
		throw new Error(
			`Native hook transaction read-back changed for ${artifact.label}; refusing to overwrite concurrent content.`,
		);
	}
	if (artifact.after === null) return;
	const content = decodeNativeHookTransactionUtf8(actual.bytes!, artifact.label);
	if (artifact.kind === "hooks") {
		const validation = validateCodexHooksConfigStrict(content, {
			platform: artifact.hookPlatform,
		});
		if (!validation.ok) {
			throw new Error(
				`Native hook transaction wrote invalid hooks.json: ${validation.error.message}`,
			);
		}
	}
	if (artifact.kind === "config") TOML.parse(content);
}

async function restoreNativeHookTransactionArtifact(
	applied: AppliedNativeHookTransactionArtifact,
	ancestorPrecondition: NativeHookTransactionAncestorPrecondition,
	tracker: RegularFileDurabilityTracker,
	assertRollbackState: () => Promise<void>,
): Promise<void> {
	const { artifact } = applied;
	const current = await captureNativeHookTransactionArtifact(artifact.path, artifact.label);
	if (!nativeHookTransactionSnapshotsEqual(current, applied.appliedSnapshot)) {
		throw new Error(
			`Native hook transaction rollback preserved ${artifact.path} for manual recovery because ${artifact.label} no longer matches the transaction-owned version.`,

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Inspect validation.error.message to see which hook entry violates the Codex hooks schema
  2. Validate your hook config with the same strict validator before starting the transaction
  3. Ensure hook command/matcher fields match the platform (hooks.json vs platform-specific format) expected by your setup version
  4. Check for non-UTF8 or truncated writes (disk issues, concurrent modifiers) by re-reading the file

Example fix

// before
const validation = validateCodexHooksConfigStrict(content, { platform: artifact.hookPlatform });
if (!validation.ok) throw new Error(validation.error.message);
// after
const validation = validateCodexHooksConfigStrict(content, { platform: artifact.hookPlatform });
if (!validation.ok) {
	console.error(`hooks.json invalid: ${validation.error.message}`);
	// abort transaction, keep prior hooks.json
	throw new Error(`Native hook transaction wrote invalid hooks.json: ${validation.error.message}`);
}
Defensive patterns

Strategy: validation

Validate before calling

import { validateCodexHooksConfigStrict } from "./setup";
const parsed = JSON.parse(hooksJson);
const check = validateCodexHooksConfigStrict(parsed, { platform: "codex" });
if (!check.ok) {
  console.error("hooks.json invalid:", check.error.message);
  process.exit(1);
}

Type guard

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
  typeof v === "object" && v !== null && !Array.isArray(v);

Try / catch

try { await runSetup(); } catch (e) { if (e instanceof Error && e.message.startsWith("Native hook transaction wrote invalid hooks.json:")) { /* keep prior hooks.json, log validation details, fix config */ } else throw e; }

Prevention

When it happens

Trigger: Calling the native hook transaction apply path with a hooks artifact whose serialized JSON fails validateCodexHooksConfigStrict for the configured hookPlatform; e.g. hook entries with wrong shape, invalid matcher syntax, or platform-specific fields missing.

Common situations: Custom hook templates with schema drift, a newer/older hooks schema version than the validator expects, encoding issues in decodeNativeHookTransactionUtf8, or test fault-injection that corrupts written bytes.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/dc7006eb01202194. Report an issue: GitHub.