readFile assumes path relative to /content and not /


I’m in the process of migrating a Google AMP page from Grow to Hugo. One aspect of that requires the CSS files to be inlined. Most examples I’ve found recommend either using a partial (as seen in a few AMP themes), or else using readFile. The partials approach isn’t ideal for me, as I use webpack to generate my CSS and related files (including fonts), and dumping them all into the partials folder leads to errors about encoding in the woff2 files, and copying just the CSS file to partials seems unnecessary.

As such, I’m trying to use readFile, which (according to the documentation) should return a string from a file, and requires a path to be given relative to the root of the project. My problem is that following the directions, I receive an error from Hugo stating that the file doesn’t exist, and lists the path. The path should be /themes/custom/static/css/style.css, but the error indicates the file path ends up being /content/themes/custom/static/css/style.css. The theme.toml and config.toml files are largely the defaults (save some unrelated language setup). This is in Hugo version 0.38.2 from the ArchLinux repositories. Is this the intended result, or is there a setting I can change somewhere?

Thanks in advance.


The truth is, we look in both. The error message is maybe confusing, but I guess you get the last “not exist” error, and not much we can do about that.

The readFile is in heavy use in the Hugo docs, and we do lots of reading from the root. Here is a en example reading layouts/shortcodes/imgproc.html:

The reason behind this “double lookup” is that we recently introduced a composite content file system (a virtual union filesystem).

So, to make readFile .Filename work, I had to do it this way. But it should be an improvement …


Hi, thank you so much for the prompt response. Now I feel really, really silly. Turns out I had made a mistake and typed “theme” instead of “themes”, and never noticed because I got too hung up on the /content part. Perhaps a warning in the documentation that it’s a sequential check of folders might help mitigate people like me posting about this.


PRs are welcomed!


I’ll pull a copy of the documentation tomorrow then.

Also, wouldn’t it be safe to re-write the error message thrown when checking for the file under /content to indicate the file wasn’t found under either path (and list both). If it’s checked sequentially, then it will always be true (as it won’t check /content if it finds it under /)?


Yes. When you have multiple content folders it gets complicated pretty fast, but I think you should avoid that in the docs…


I wasn’t talking about putting it in the docs. I was just thinking that one could re-word the error that hugo throws. Because:

if pathA exists then [...] else if pathB exists then [...] else [...]

Essentially (from what I understand about Go and what you’ve said), it sounds like it checks the root path (pathA) first. If that doesn’t exist, it then checks the content path (pathB). And if pathB doesn’t exist, neither one exists. Therefore the error message could indicate that neither path exists. It would be a bit more descriptive. Admittedly, I haven’t looked at the actual readFile code (I’m not even sure what file it would be found in) so the approach could be different.


It is a virtual filesystem (Afero), and that is not supported. It can potentially be hundreds … Up to the user.