The presence of a page or post with no content breaks the Content API
Issue Summary
Requesting pages or posts from the content API when a one post/page has no 'body' content fails, throwing the error below.
Steps to Reproduce
Create a new post or page in the Ghost editor. Do not put any content in the page. (Do give it a title.) Hit publish.
Attempt to retrieve pages via the content API (probably with limit=all so you're sure to hit it).
Ghost Version
5.108-5.114
Node.js Version
20
How did you install Ghost?
cli (production install)
Database type
MySQL 8
Browser & OS version
any
Relevant log / error output
Error [InternalServerError]: Internal server error, cannot list pages.
at /home/cathy/algolia index/node_modules/@tryghost/content-api/cjs/content-api.js:271:37
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async TypeCommand.run [as _runHandler] (/home/cathy/algolia index/node_modules/@tryghost/algolia/bin/cli.js:83:29)
at async Promise.all (index 2) {
context: 'An unexpected error occurred, please try again. Minified Lexical error #38; visit https://lexical.dev/docs/error?code=38 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.',
^^ although the error above was thrown while trying to index a site, I get the same error by making a GET request with the browser - it doesn't look to be Algolia or SDK-related.
Code of Conduct
- [x] I agree to be friendly and polite to people in this repository
@cathysarisky š Hi, Iām a first-time contributor to Ghost and would love to take on this issue. Could you please assign it to me? Thanks!
@cathysarisky š Hi, Iām a first-time contributor to Ghost and would love to take on this issue. Could you please assign it to me? Thanks!
Sorry, I don't have write permissions on the repo. But I can tell you that the core team typically doesn't assign issues to new contributors. [Probably due in part to a lot of drive-by "please assign to me" that never produces code or even a second visit.] So if you want to work on it, feel free to post here that you are, and then file a PR when done! contributing.md is a good place to start for links to how to set up your dev environment, etc.
And welcome to Ghost! :)
@cathysarisky Hi! I just set up Ghost locally following the contribution guide and tried to reproduce the issue. I created both a post and a page with only a title (no body content), published them, and then made a request to the Content API. However, the response came back successfully, and everything looked fine on my end. As you can see that the api did respond all the posts including the one I created with just the title "test".
Hey @luoxixiang23921 , thanks for trying to reproduce! I tried on a local install with the latest (5.116), and couldn't reproduce it. I went back to the production site running 5.114 (where I'd previously seen the problem on 5.108 also), and it was still there. I rolled back a local install to 5.112, and couldn't reproduce. I tried my ghost pro site and couldn't reproduce (which would seem to rule out this being a MySQL bug that doesn't reproduce on local installs).
So... I am guessing the problem is a quirk of my prod site? I'll be interested to see if it persists after my next update.
Closing the issue, since while I can reproduce it on one site, that's not enough for anyone else to bug chase it!
@cathysarisky did this ever pop up for you again/eventuallly got resolved? I am having the exact same issue with a customer's site and narrowed it down to 6 (very old) posts, while also trying to index stuff for search.
Hey @betschki , no, I haven't seen it again, although I haven't tried very hard to find it, giving the only place I've seen it is my prod site, where I try to limit my monkeying around.
Possibly useful info about that site: Ghost-CLI install in a Ubuntu VPS. (So it's not uniquely something about your Docker/K8 setup) Fairly recent (~9 months), BUT has content back to like '22, that I imported via an exported json file from my old install. I wondered if it was an old imported/converted mobiledoc issue, but it happens with brand new posts, too.
Interesting. The 6 posts are ranging from 2014 to 2021. The oldest ones were definitely imported at some point, but all of them were mobiledoc. We have tried to re-save them in the Ghost editor, which did convert them to proper (and valid) lexical, but the issue remains.
I'll try to get more information on how the stuff was added into Ghost and will report back here.
Quick update: Creating an entirely new post in my prod setup without post content still causes this error.
{"errors":[{"message":"Internal server error, cannot list posts.","context":"An unexpected error occurred, please try again. Minified Lexical error #38; visit https://lexical.dev/docs/error?code=38 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.","type":"InternalServerError","details":null,"property":null,"help":null,"code":"UNEXPECTED_ERROR","id":"e8590090-363c-11f0-b6b0-c5d04c6a814f","ghostErrorCode":null}]}
That's 5.120, so definitely still live, although maybe only for sites with old imported posts. My oldest posts are definitely from the mobiledoc era.
Fuller error from the server's error log:
{
"name": "Log",
"hostname": "srv650399",
"pid": 582646,
"level": 50,
"version": "5.120.0",
"req": {
"meta": {
"requestId": "64af0168-31bf-465c-8ec5-fed47f44614c",
"userId": null
},
"url": "/posts/?key=07362f425d6a52589ad9f7fcb1&limit=all",
"method": "GET",
"originalUrl": "/ghost/api/content/posts/?key=07362f425d6a52589ad9f7fcb1&limit=all",
"params": {},
"headers": {
"x-forwarded-for": "*redacted*",
"x-forwarded-proto": "https",
"x-real-ip": "*redacted*",
"host": "*redacted*",
"connection": "close",
"cf-ray": "943402a5e91d1752-IAD",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-encoding": "gzip, br",
"cdn-loop": "cloudflare; loops=1",
"priority": "u=0, i",
"accept-language": "en-US,en;q=0.9,ar;q=0.8,de;q=0.7",
"cf-visitor": "{\"scheme\":\"https\"}",
"sec-fetch-dest": "document",
"sec-fetch-user": "?1",
"cf-connecting-ip": "204.111.114.99",
"cf-ipcountry": "US",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-ch-ua": "\"Chromium\";v=\"136\", \"Google Chrome\";v=\"136\", \"Not.A/Brand\";v=\"99\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"dnt": "1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
"cookie": "**REDACTED**"
},
"query": {
"key": "**REDACTED**",
"limit": "all"
}
},
"res": {
"_headers": {
"x-powered-by": "Express",
"content-version": "v5.120",
"vary": "Accept-Version, Accept-Encoding",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"access-control-allow-origin": "*",
"content-type": "application/json; charset=utf-8",
"content-length": "475",
"etag": "W/\"1db-BRVni2Zc0H9iFkD0Dj739PgFos8\""
},
"statusCode": 500,
"responseTime": "43ms"
},
"err": {
"id": "8ca6ec20-363d-11f0-b6b0-c5d04c6a814f",
"domain": "*redacted*",
"code": "UNEXPECTED_ERROR",
"name": "InternalServerError",
"statusCode": 500,
"level": "critical",
"message": "An unexpected error occurred, please try again.",
"context": "\"Minified Lexical error #38; visit https://lexical.dev/docs/error?code=38 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\"",
"stack": "Error: Minified Lexical error #38; visit https://lexical.dev/docs/error?code=38 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.\n at prepareError (/var/www/sws/versions/5.120.0/node_modules/@tryghost/mw-error-handler/lib/mw-error-handler.js:113:19)\n at n (/var/www/sws/versions/5.120.0/node_modules/lexical/Lexical.prod.js:8:128)\n at Gf.setEditorState (/var/www/sws/versions/5.120.0/node_modules/lexical/Lexical.prod.js:196:390)\n at LexicalHTMLRenderer.render (/var/www/sws/versions/5.120.0/node_modules/@tryghost/kg-lexical-html-renderer/build/LexicalHTMLRenderer.js:67:16)\n at async Object.render (/var/www/sws/versions/5.120.0/core/server/lib/lexical.js:83:16)\n at async Child.renderIfNeeded (/var/www/sws/versions/5.120.0/core/server/models/post.js:392:26)\n at async Child.onFetched [as onFetchedCollection] (/var/www/sws/versions/5.120.0/core/server/models/post.js:384:13)",
"hideStack": false
},
"msg": "An unexpected error occurred, please try again.",
"time": "2025-05-21T12:17:22.915Z",
"v": 0
}
Other tidbits: The error is not thrown if the blank post is not included in the results. (i.e. by limiting or filtering)
I spent some time digging into this, since it blocks the usage of my search feature for some customers. I found many red herrings on the way, but finally have the culprit earlier today: the collectionsCard lab flag.
Wrote a fix for it and just wanted to add the PR, but @kevinansfield removed the entire flag a few hours ago: https://github.com/TryGhost/Ghost/commit/24edbf496b2bd6bd6f1573b30624963033c53ddb.
My assumption: after this is released it should work again š
The lab flag caused an empty editor state being passed to the Koenig HTML renderer, which threw the error. This party specifically was responsible, but is now removed:
https://github.com/TryGhost/Ghost/commit/24edbf496b2bd6bd6f1573b30624963033c53ddb#diff-3149f93d170c65cd0c97a204a2d19c6102351b3c542c357aa342874699521237L371-L373
Nice debugging!
I definitely had the collectionsCard flag set. In addition to this, it may also have been responsible for the weird behavior I reported in #23356. At least, I hope so, because I'd like it gone. :)