FAQ
This page collects common errors and their solutions during blog usage. Each problem follows a symptom → cause → solution structure; commands can be copied directly.
1. Cache Not Taking Effect (changes don’t show)
Symptom: after changing config/styles/posts, the built page is still old; or browsers/PWA keep showing the old version.
Cause: three layers of cache stack up — the Hexo incremental cache (db.json), the hexo server memory cache, and browser/PWA Service Worker cache. Rule them out layer by layer, starting from the outermost:
Solution:
# ① first confirm whether it's a build output problem or a browser problem
curl -s http://localhost:4000/ | grep "keyword" # does the server return old or new?
# ② build cache: hexo clean is the official cleanup (deletes db.json + public + resets internal cache)
# ⚠️ don't substitute rm -rf public db.json — it doesn't reset hexo's internal cache state
hexo clean && hexo generate
# ③ server memory cache (inside the Docker container): pm2 restart isn't enough, delete db.json
pm2 stop hexo_run && rm -f /app/db.json && pm2 start hexo_run// ④ browser/PWA cache: after changing JS/CSS you MUST bump the version (-r release), otherwise the SW serves the old version
navigator.serviceWorker.getRegistrations() // inspect SW in console; unregister before verificationPrevention: use tools/cicd.sh -r to bump the version for JS/CSS changes; -c for content-only changes (see the release flow selection in the Deployment chapter).
2. db.json Permission / Data Cache Conflicts
Symptom:
FATAL Error: EACCES: permission denied, open '/app/db.json'
FATAL Error: EACCES: permission denied, unlink '/app/db.json'Or: pages go blank after changing source/_data/*.yml data files (site.data.xxx undefined).
Cause: the Docker container runs as root by default; files created in bind-mounted host directories are owned by root, so the host user can’t delete them → EACCES. Blank pages from data files are the Hexo incremental cache misjudging “already cached, unchanged” (the Cache hash updates but the Data model isn’t written).
Solution:
# permissions: fix ownership inside the container
fix_perms() {
local owner=$(stat -c '%u:%g' /app)
chown -R "$owner" /app/db.json /app/public/ /app/.cache/
}
fix_perms && hexo clean
# data cache: must delete db.json before generate
rm -f db.json && hexo generate
# container 4000 preview: pm2 stop → rm -f /app/db.json → pm2 start (restart without deleting db is useless)
# root fix: specify a user in docker-compose.test.yml
# services.hexo.user: "${PUID:-1000}:${PGID:-1000}"Delete db.json before verifying data loading, otherwise you read the old cache and get a false pass.
3. Build Failures (post_link / unknown block tag)
Symptom:
Cannot find post with slug: xxx # post link broken
Error: Unable to locate template: xxx # template not found
unknown block tag: xxx # custom tag misspelled or registration failedCause: the post post_link points to doesn’t exist or its slug changed; {% xxx %} uses an unregistered or misspelled tag; wrong template path.
Solution:
# ① first locate the failing file and line (the build output gives it)
npx hexo generate 2>&1 | grep -A2 "FATAL\|Error"
# ② post_link: confirm the target post exists; use the filename or the front-matter slug
# this blog uses abbrlink permalinks; use post_link + title for inter-post links
{% post_link post-title %}
# ③ unknown block tag: check whether the tag is registered under themes/matery/scripts/tags/,
# and whether it was written in inline form ({% tag %} without closing vs {% tag %}...{% endtag %})
# ④ build hangs: when hexo generate outputs nothing, use --debug to watch progress
npx hexo generate --debugPrevention: after changing scripts under scripts/, always hexo clean before generate (a plain generate may reuse old output — cost an hour of debugging once).
4. Comments Not Showing
Symptom: no comment box at the bottom of posts, or a blank comment area.
Cause: three layers of switches — the global switch, the front-matter switch, and the Waline serverURL config.
Solution:
# ① theme config (userConfig/_config.tmp.yml):
# find the waline section, confirm enable: true and a correct serverURL
serverURL: 'https://waline.17lai.site' # comment service address
# ② post front-matter: did it disable comments?
---
comments: true # false or missing (depends on the template default) both hide comments
---# ③ verify the service is reachable
curl -sI https://waline.17lai.site | head -3Note: the comment injection point (postComments) is called in templates — confirm the waline template under layout/_partial/comments/ isn’t commented out; clear caches per section 1 after config changes.
5. Dark Mode Issues (–font-scale / CSS variables)
Symptom: text illegible or colors scrambled after switching to dark; or font sizes off (--font-scale reset).
Cause: the theme implements dark mode with CSS variables ([data-user-color-scheme="dark"]); font sizes are rem-based, scaling with --font-scale. Issues are mostly: CSS variables overridden by hardcoded colors, the font scale modified, or browser zoom preferences interfering.
Solution:
// ① confirm dark variables apply in the console
getComputedStyle(document.documentElement).getPropertyValue('--body-bg-color')
// ② font size issues: check whether the font scale was modified (rem-based, scales with --font-scale)
// font_size_* series in themes/matery/_config.yml or templates
// --font-scale is set by JS per browser/user preference; confirm localStorage has no stale leftovers
// ③ style override checks: don't force-override theme variables with !important (breaks lower-layer styles),
// reference CSS variables with var(--xxx) in custom stylesPrinciple: custom colors must use CSS variables like var(--card-bg-color) (three-layer architecture: config → Stylus variables → CSS variables), never hardcode #333 (see the Customization chapter).
6. Language Switching Not Working (localStorage)
Symptom: clicking the trad/simp or language switch button doesn’t change the page, or it reverts on refresh.
Cause: the language preference is stored in localStorage; the switching logic reads theme.preference config in the corresponding JS. Not working usually means: JS cached (old version without the feature), localStorage cleared/disabled, or the config switch turned off.
Solution:
// ① check the preference value and config in the console
localStorage.getItem('language') // language preference (actual key per code)
localStorage.removeItem('xxx') // clear stale leftovers, then refresh
// ② confirm the switch: the preference section of the theme config
// translate: Chinese trad/simp conversion (consolidated into preference.translate on 2026-08-16)
// the legacy footer.translate was removed on 2026-08-10; only preference.translate.enable is read
// ③ still not working → follow section 1 cache troubleshooting (version not bumped, browser running old JS)Prevention: for config changes affecting JS behavior, release with -r so the version changes (?v=xx updates, browsers fetch the new version).
Appendix: Troubleshooting Order (follow this first)
| Step | Check | Command |
|---|---|---|
| 1 | build log for errors | npx hexo generate 2>&1 \| grep -i error |
| 2 | build output updated | curl -s site-URL \| grep keyword |
| 3 | cache cleanup | hexo clean && hexo generate |
| 4 | server memory cache | pm2 stop && rm -f db.json && pm2 start |
| 5 | browser/PWA cache | version bump (-r) + unregister SW |
| 6 | actual config values | grep key-name userConfig/_config.tmp.yml |