Issue using app.fileManager.processFrontmatter

I’ve been trying to change the frontmatter from within a Templater template, and it mostly goes OK, with the exception on when the frontmatter is present, but empty like in the following file:

---
---
Empty frontmatter

In this particular case I can’t seem to insert a new value. Is this just me doing it the wrong way, or is this a bug/feature of either Obsidian and/or Templater? Could someone enlighten me, as to what to do with this, or how to insert a value into the empty frontmatter?

Files used for testing

I’ve got three files to show this behavior:

---
Something: Somevalue
---
NiceFrontmatter.md
---
---
EmptyFrontmatter.md
NoFrontmatter.md

Each block is a file named like the body text

My Templater template to trigger behavior
<%*
const filenames = [
  'NiceFrontmatter', 
  'NoFrontmatter', 
  'EmptyFrontmatter' ]

for (let name of filenames) {
  const theFile = await tp.file.find_tfile(name)
  const suggestion = tp.date.now("HH:mm:ss SSS")
  
  await app.fileManager.processFrontMatter(theFile, (fm) => {
    console.log(suggestion, theFile.name, fm)
    if (fm == null) {
	  console.log('Big red flag')
      fm =  { 'Nothing' : 'No value' }
	} else {
	  fm['Created'] = suggestion
	}
  })
  console.log("done")
}
%>
Result after inserting the template

A screenshot of the Console from Developers Tool:
image

Both NiceFrontmatter.md and NoFrontmatter.md got the Created: 19:27:18 ... values, but as shown in the screenshot the EmptyFrontmatter.md has got fm == null and fails miserably when trying to set the fm (which is to be expected). I’ve also tried returning a new dictionary, like in return {} (or similar), but that fails as well.

Can replicate - looks like a bug. (unless the YAML spec requires that there be some content)

1 Like

Will be fixed in a upcoming release.
Thanks for the report.

2 Likes

Thanks a lot! And I understand it correctly, that I don’t need to do anything else, but just wait for that upcoming release?

For those impatient, I found a workaround where I throw a custom error message from within app.fileManager.processFrontmatter, and then read the entire file, do a regex replace, before writing the modified file back again. Not for the faint of heart, but it seems to work.

A workaround using try-catch -> app.read/app.modify

For those impatient, the following seems to work as a workaround:

<%*

function emptyFrontmatter(newFrontmatter) {
  this.message = newFrontmatter
  this.name = 'emptyFrontmatter'
}

const filenames = [
  'NiceFrontmatter', 
  'NoFrontmatter', 
  'EmptyFrontmatter' ]

for (let name of filenames) {
  const theFile = await tp.file.find_tfile(name)
  const suggestion = tp.date.now("HH:mm:ss SSS")

  try {
    await app.fileManager.processFrontMatter(theFile, (fm) => {
      console.log(suggestion, theFile.name, fm)
      if (fm == null) {
        throw new emptyFrontmatter({'Created': suggestion})
	  } else {
	    fm['Created'] = suggestion
  	  }
    })
  } catch (e) {
    if (e.name == 'emptyFrontmatter') {
      let str = "---\n" +
                Object.entries(e.message)
                      .map(([fieldName, value]) => 
                           `${fieldName}: ${value}`).join("\n") +
                "\n---"

	  let content = await app.vault.read(theFile)
      content = content.replace(/^---\n(?:\s*\n)*---/g, str)
      // console.log(content)
      await app.vault.modify(theFile, content)
    } else 
      throw e
            
  } finally {
    console.log('done')
  }
}
%>

Not entirely sure if my mapping will work in all cases, so care should be taken especially if using arrays or links or more complex objects to be inserted in the frontmatter.

Disclaimer: As always, use at your own risk! :smiley:

Correct, just wait, the frontmatter should never be null in the next release.

As for your workaround, it will work as long as nothing else is writing to that file at that moment.

1 Like

@joethei, could this issue also be effecting the iOS app? I have a custom plugin that adds front-matter to notes that typically don’t already have front-matter. While it’s a bit hard to troubleshoot, I’m fairly confident the following code is throwing an error on iOS:

await app.fileManager.processFrontMatter(view.file, (fm) => {
  fm["tags"] = ['test'];
  ...
});

Any insights you could provide would be appreciated.

In my case, the issue was only when there was an empty frontmatter, not when the frontmatter was completely missing.

This API was added in v1.1.0, so if you are using the normal build and not the insider build this will crash.

Gotcha. Installing the Insider built fixed the issue. Thanks @joethei !

I’m (kind of patiently) waiting for the ordinary release, as I’m not an insider, yet. I’m just this random dude wanting this… :smiley: