fix: tolerate malformed YAML frontmatter when parsing note metadata - #132
Merged
Conversation
PR #130 added a live-parse fallback in parseFrontmatterContent for notes whose frontmatter range Obsidian's cache doesn't report, but it called parseYaml unguarded. A note starting with --- whose YAML is malformed (e.g. 'status: : :') therefore threw, aborting controller.getPropertiesInFile() for the whole note and dropping its inline and tag metadata. Wrap the live parse in try/catch and treat malformed YAML as non-parseable (return null), mirroring the bulk preflight's BulkMetadataEditor.readLiveFrontmatter. Returning null preserves the existing cache fallback, so a note that is only momentarily unparseable mid-edit still surfaces its last-known-good cached frontmatter rather than dropping it. Adds a unit regression (parseYaml mocked to throw, since the test stub's parseYaml is permissive) and a live Obsidian E2E regression that reproduces the real throw and asserts inline and tag metadata still surface.
github-actions Bot
pushed a commit
that referenced
this pull request
Jul 1, 2026
# [1.9.0](1.8.4...1.9.0) (2026-07-01) ### Bug Fixes * address review findings from PRs [#119](https://github.com/chhoumann/MetaEdit/issues/119)-[#128](https://github.com/chhoumann/MetaEdit/issues/128) ([adf0b57](adf0b57)) * **api:** preserve reserved keys when cloning values ([#162](#162)) ([cff6076](cff6076)) * **automators:** count only [x]/[X] tasks complete; null-guard Kanban lane display ([#145](#145)) ([21da53a](21da53a)) * **bulk:** reject __proto__/constructor as a bulk property key ([#148](#148)) ([f03eacc](f03eacc)) * **bulk:** serialize bulk frontmatter writes through the controller write queue ([#147](#147)) ([3eb8236](3eb8236)) * **controller:** guard __proto__/constructor in all frontmatter writes ([#159](#159)) ([9d99fae](9d99fae)) * **controller:** make inline-field writes fence-aware ([5f8e713](5f8e713)) * **core,api:** safe command no-op, block-list deletion, presence-based property lookups ([#143](#143)) ([1702d08](1702d08)) * edit YAML lists (incl. tags) as native lists instead of collapsing them to a string ([#94](#94)) ([#128](#128)) ([79f6ee0](79f6ee0)), closes [#51](#51) [#36](#36) * harden frontmatter metadata writes ([add2e90](add2e90)) * Kanban helper syncs only the card's leading link, not trailing date/reference links ([#126](#126)) ([52aec1e](52aec1e)) * **kanban:** don't write to an ambiguous same-named note ([#158](#158)) ([7f9655b](7f9655b)) * **kanban:** single notice for a card missing the board property ([9b1c88a](9b1c88a)) * parse inline fields behind list/quote markers and brackets ([#122](#122)) ([a62ef21](a62ef21)), closes [#119](#119) [#18](#18) [#121](#121) [#78](#78) [#84](#84) * **parser:** preserve [[wikilinks]] in multi-value inline edits ([c331adb](c331adb)) * **settings:** serialize Auto Property choice persistence to prevent lost updates ([#154](#154)) ([2066b3e](2066b3e)) * **settings:** settings tab no longer clobbers concurrently-added Auto Property choices ([5759534](5759534)) * **settings:** validate auto-properties before queueing and make rollbacks compare-and-restore ([#156](#156)) ([8cbacdc](8cbacdc)), closes [#154](#154) * stop inline-field updates appending a stray bracket ([#127](#127)) ([d2617f5](d2617f5)), closes [#67](#67) [#121](#121) * **suggester:** center row action icons flush-right ([#166](#166)) ([c00795e](c00795e)) * **suggester:** use native icons + tooltips for row actions ([70903cc](70903cc)) * **suggester:** well-formed duplicate Notice, robust modal close, cleaner name suggestions ([#144](#144)) ([915dd6b](915dd6b)), closes [#143](#143) * **tags:** correct and clarify tag editing ([#142](#142)) ([b837899](b837899)), closes [#49](#49) * tolerate malformed YAML frontmatter when parsing note metadata ([#132](#132)) ([b835f97](b835f97)), closes [#130](#130) ### Features * adopt modern Obsidian APIs and raise baseline ([5131664](5131664)) * **api:** append Dataview field instances without replacing ([42c78a8](42c78a8)), closes [#91](#91) * **api:** expand public integration surface ([#120](#120)) ([bbf0a7a](bbf0a7a)) * assist property-value entry with autocomplete and a native date picker ([#125](#125)) ([cd86235](cd86235)), closes [#61](#61) [#74](#74) [#61](#61) [#61](#61) * **auto-properties:** description, multi-select, and learn-as-you-go values ([#123](#123)) ([4b24296](4b24296)), closes [#59](#59) [#40](#40) [#59](#59) [#40](#40) [#59](#59) [#40](#40) [#43](#43) [#30](#30) * **auto-properties:** paste a list to split into choices ([#139](#139)) ([0245f7a](0245f7a)) * bulk edit metadata across folders and selected notes ([#124](#124)) ([c8d91e2](c8d91e2)), closes [#64](#64) [#20](#20) * **create:** fluid, type-aware native YAML property creation ([#170](#170)) ([59b4c5d](59b4c5d)) * **editor:** edit properties with Obsidian's native widgets; raise minAppVersion to 1.12.7 ([#168](#168)) ([73b37e0](73b37e0)) * hide file tags from the Edit Meta menu ([#46](#46), [#90](#90)) ([#131](#131)) ([2c07937](2c07937)), closes [#tag](https://github.com/chhoumann/MetaEdit/issues/tag) [#tags](https://github.com/chhoumann/MetaEdit/issues/tags) * support nested YAML path editing ([e9fce98](e9fce98))
|
🎉 This PR is included in version 1.9.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tolerate malformed YAML frontmatter so a note's metadata parse never aborts on bad frontmatter; inline
key:: valuefields and tags still surface.Why
PR #130 added a live-parse fallback in
parseFrontmatterContent(src/parser.ts) for notes whose frontmatter range Obsidian's metadata cache doesn't report (e.g. a read-after-write race). That path calledparseYamlunguarded. A note starting with---whose YAML is malformed - for example:gives Obsidian no usable frontmatter cache, so the live-parse path runs and
parseYamlthrows. The throw propagated out ofparseFrontmatter->controller.getPropertiesInFile()-> the Run MetaEdit command, aborting the parse for the whole note and dropping its inline/tag metadata. The post-merge Codex review on #130 flagged exactly this.Fix
Wrap the live
parseYamlcall intry/catchand treat malformed YAML as non-parseable (return null), mirroring the bulk preflight'sBulkMetadataEditor.readLiveFrontmatter, which already catches the identical failure. Returningnull(rather than[]) preserves the existing cache fallback chain, so a note that is only momentarily unparseable mid-edit still surfaces its last-known-good cached frontmatter instead of dropping it - consistent with howparseFrontmatteralready degrades when there is no live frontmatter range.Tests
src/parser.test.ts): assertsparseFrontmatterswallows a thrownparseYamland resolves to[]; that it falls back to cached frontmatter when the live parse throws; and that inline fields still surface (incl. CRLF). The shared obsidian test stub'sparseYamlis a permissive line parser that never throws, so the throw is simulated withvi.spyOn.tests/e2e/metaedit-runtime.test.ts): reproduces the real Obsidian throw withstatus: : :and assertsgetPropertiesInFilereturns the inlinefoo:: barand the#mytagtag with no runtime errors. Polls the metadata cache for the tag to avoid an indexing-timing flake.Verification
Reproduced live first in an isolated Obsidian E2E vault (Obsidian 1.x): pre-fix
getPropertiesInFilethrewNested mappings are not allowed in compact mappings; post-fix it returns[#mytag, foo:: bar]and the Run MetaEdit command opens the suggester without error. Live edge-case sweep (empty frontmatter, only-malformed-key, bad indentation, tab indentation, CRLF, and a valid-frontmatter control) all pass.Commands run:
pnpm run lint(0 errors),pnpm run build,pnpm run test(178 passed), fulltests/e2esuite (40 passed).Refs #130
🤖 Generated with Claude Code