{"record":{"id":"83c861ba832847b3","repo":"can1357/oh-my-pi","slug":"config-overlay-must-be-a-yaml-mapping-filepath","errorCode":null,"errorMessage":"Config overlay must be a YAML mapping: ${filePath}","messagePattern":"Config overlay must be a YAML mapping: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/config/settings.ts","lineNumber":1601,"sourceCode":"\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = await Bun.file(filePath).text();\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\tisEnoent(error)\n\t\t\t\t\t? `Config overlay not found: ${filePath}`\n\t\t\t\t\t: `Failed to read config overlay ${filePath}: ${String(error)}`,\n\t\t\t);\n\t\t}\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = YAML.parse(content);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to parse config overlay ${filePath}: ${String(error)}`);\n\t\t}\n\t\tif (parsed === null || parsed === undefined) return {};\n\t\tif (typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\t\tthrow new Error(`Config overlay must be a YAML mapping: ${filePath}`);\n\t\t}\n\t\treturn this.#migrateRawSettings(parsed as RawSettings, captureLegacyChangelogVersion);\n\t}\n\n\tasync #migrateFromLegacy(): Promise<void> {\n\t\tif (!this.#configPath) return;\n\n\t\tlet settings: RawSettings = {};\n\t\tlet migrated = false;\n\n\t\t// 1. Migrate from settings.json\n\t\tconst settingsJsonPath = path.join(this.#agentDir, \"settings.json\");\n\t\ttry {\n\t\t\tconst parsed: unknown = JSONC.parse(await Bun.file(settingsJsonPath).text());\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n\t\t\t\tsettings = this.#deepMerge(settings, this.#migrateRawSettings(parsed as RawSettings));\n\t\t\t\tmigrated = true;\n\t\t\t\ttry {","sourceCodeStart":1583,"sourceCodeEnd":1619,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/config/settings.ts#L1583-L1619","documentation":"After successful YAML parsing, Settings requires the overlay document to be a YAML mapping (an object). If the document parses to an array, a scalar, or any non-object value, the loader refuses it because overlays are merged as key/value maps. This keeps partial-application semantics well-defined.","triggerScenarios":"An overlay file whose top level is a YAML list (e.g. `- a\\n- b`), a bare string/number, or a document that resolves to only a scalar; also YAML files containing just a comment or `---` with no mapping.","commonSituations":"Someone pasted an array of settings entries instead of an object; a user wrote `settings: ...` content at the wrong nesting level leaving only a scalar; an empty file plus a stray `-` list item.","solutions":["Wrap the overlay content in a top-level mapping: `key:\\n  subkey: value` instead of a list or bare value.","If the file should be empty, empty it entirely (null/empty documents are tolerated and treated as {}).","Check that you didn't lose the top-level keys when editing — move list items under a mapping key."],"exampleFix":"// before (parses as an array)\n- model: gpt-5\n- agent: build\n// after\noverrides:\n  model: gpt-5\n  agent: build","handlingStrategy":"validation","validationCode":"const doc = YAML.parse(await readFile(overlayPath, \"utf8\"));\nif (doc !== null && (typeof doc !== \"object\" || Array.isArray(doc))) {\n  throw new Error(`${overlayPath} must contain a top-level YAML mapping`);\n}","typeGuard":"function isMapping(v: unknown): v is Record<string, unknown> {\n  return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}","tryCatchPattern":null,"preventionTips":["Always keep at least one top-level `key:` mapping in overlay files.","Use empty file (or only comments) to mean 'no overrides' — empty/null is accepted.","Schema-check overlays against your settings keys before loading."],"tags":["yaml","config","validation"],"backgroundTag":"config-schema-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}