Yeachan-Heo/oh-my-codex · error · Error
sandbox.md frontmatter evaluator.keep_policy must be a strin
Error message
sandbox.md frontmatter evaluator.keep_policy must be a string when provided.
What it means
parseKeepPolicy throws when sandbox.md frontmatter defines evaluator.keep_policy but its value is not a string (e.g. a number, boolean, or nested map). The parser only accepts a string (or omission/empty, which means undefined).
Source
Thrown at src/autoresearch/contracts.ts:138
const section = result[currentSection];
if (!section || typeof section !== 'object' || Array.isArray(section)) {
throw contractError(`Invalid sandbox.md frontmatter section: ${currentSection}`);
}
(section as Record<string, unknown>)[key] = value;
continue;
}
result[key] = value;
currentSection = null;
}
return result;
}
function parseKeepPolicy(raw: unknown): AutoresearchKeepPolicy | undefined {
if (raw === undefined) return undefined;
if (typeof raw !== 'string') {
throw contractError('sandbox.md frontmatter evaluator.keep_policy must be a string when provided.');
}
const normalized = raw.trim().toLowerCase();
if (!normalized) return undefined;
if (normalized === 'pass_only') return 'pass_only';
if (normalized === 'score_improvement') return 'score_improvement';
throw contractError('sandbox.md frontmatter evaluator.keep_policy must be one of: score_improvement, pass_only.');
}
export function parseSandboxContract(content: string): ParsedSandboxContract {
const { frontmatter, body } = extractFrontmatter(content);
const parsedFrontmatter = parseSimpleYamlFrontmatter(frontmatter);
const evaluatorRaw = parsedFrontmatter.evaluator;
if (!evaluatorRaw || typeof evaluatorRaw !== 'object' || Array.isArray(evaluatorRaw)) {
throw contractError(EVALUATOR_BLOCK_ERROR);
}
const evaluator = evaluatorRaw as { command?: unknown; format?: unknown; keep_policy?: unknown };View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Set keep_policy to one of the quoted or unquoted string values: score_improvement or pass_only, e.g. 'keep_policy: pass_only'.
- Remove the key entirely if you want the default policy.
- Ensure it is a single scalar line, not an indented block.
Example fix
# before
evaluator:
keep_policy:
policy: pass_only
# after
evaluator:
keep_policy: pass_only Defensive patterns
Strategy: type-guard
Validate before calling
import { parseSandboxContract } from './contracts'; // parse first; keep_policy type errors surface here
// or pre-check the raw YAML value yourself before parsing:
function keepPolicyIsString(raw: unknown): boolean {
return raw === undefined || typeof raw === 'string';
} Type guard
const isKeepPolicyShaped = (raw: unknown): boolean => raw === undefined || (typeof raw === 'string' && (['', 'pass_only', 'score_improvement'].includes(raw.trim().toLowerCase())));
Try / catch
try {
parseSandboxContract(content);
} catch (err) {
if ((err as Error).message.includes('keep_policy must be a string')) {
// replace structured keep_policy with a scalar 'pass_only'/'score_improvement' or remove it
}
throw err;
} Prevention
- Write keep_policy as a single scalar line.
- Never use an indented block or number/boolean for keep_policy.
When it happens
Trigger: Frontmatter containing 'keep_policy: 2', 'keep_policy: true', or an indented block under keep_policy; parseSandboxContract passes evaluator.keep_policy into parseKeepPolicy and the typeof check fails.
Common situations: Quoting mistakes that still parse to non-strings in this simple parser, YAML booleans/numbers written without quotes where a policy name was intended, or copy-pasting a structured policy object.
Related errors
- sandbox.md must start with YAML frontmatter containing evalu
- Unsupported sandbox.md frontmatter line: ${trimmed}
- Nested sandbox.md frontmatter key requires a parent section:
- Invalid sandbox.md frontmatter section: ${currentSection}
- sandbox.md frontmatter evaluator.keep_policy must be one of:
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/0117cc99472fc7db.
Report an issue: GitHub.