Repository navigation
Conversation
…limit The search API answers HTTP 400 to any query over 50 characters, and full novel titles such as "Reincarnation Of The Strongest Sword God (Web Novel)" exceed that. The 400 body carries no `data`, so searchNovels threw "Cannot read properties of undefined (reading 'items')". Trim queries to a word boundary before sending them, for search and the keyword filter. Bump version to 2.1.4.
[Medium impact] The PR appears safe to merge; no actionable issues were found. SummaryUpdates NovelBuddy search and bumps the plugin version to
Acknowledgments in RibatTRW's supplied PR description: the misleading error for a successful response without Reviews (1) · Last reviewed commit: "no-mistakes(document): soften clampQuery..." · Reviewed by Greptile |
This branch has not been deployed
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.
Intent
Fix the broken novelbuddy source so a reader can search it again, and include screenshots of the working fix in the PR.
plugins/english/novelbuddy.ts works for browsing and reading, but search does not: the plugin's own live check fails searchNovels with
Cannot read properties of undefined (reading 'items'), while the site's search API (api.novelbuddy.me/titles/search) answers 200 with about 64 KB of data. So the site is up and returning search results - the plugin is reading an envelope that no longer exists. This is one of the plugins this fleet's plugin health sweep confirmed as genuinely broken today (not a site-side block).Make sure the fix's pull request shows a photo of the plugin working correctly inside the plugin playground, and run that screenshot process headless if possible.
What Changed
searchTitleshelper that checks the HTTP status and throws a clearNovelBuddy search failed with HTTP <status>error when the response is not OK or has nodata.items, instead of failing with an undefined-property error. Both the filtered popular-novels search and the search-by-term path use it.clampQuery) before being sent, avoiding HTTP 400 responses from the search API for longer queries. The cut never leaves a lone surrogate half.Risk Assessment
🚨 High: The change does not touch the response parsing that the reported failure points to, so the stated search breakage is likely still present, and the query-trim rationale is unverified in the repo.
Testing
Reproduced the reported failure with
npm run check:pluginagainst the base commit (searchNovels FAIL with the exact TypeError), then confirmed the target commit passes all four live steps (popularNovels, searchNovels, parseNovel, parseChapter). Stood up the real playground (Vite on a loopback address so the playground's hardcoded localhost:3000 proxy matches, because ports 3000-3004 were held by other sessions), drove NovelBuddy's Search tab in headless Chromium, and captured screenshots of a 52-character title search returning results. Also drove a 150+ character query (the network request was confirmed as the 50-character clamp), a short query, and a 49-ASCII-character plus emoji query that stays error-free. Probed api.novelbuddy.me directly to confirm the 50-character boundary (50 returns 200, 51 returns 400). Cleaned up the dev server, headless browser, generated multisrc output, and temp files; the worktree is clean.npm run check:pluginoutput for base commit 49b4727 (temporary copy, removed afterwards): searchNovels FAIL 'Cannot read properties of undefined (reading 'items')'npm run check:plugin -- plugins/english/novelbuddy.tsoutput: all four PASS~/.no-mistakes/evidence/01M4ZP064CS74MD9J4PPS1G1Y6/novelbuddy-search-long-query-playground.png)~/.no-mistakes/evidence/01M4ZP064CS74MD9J4PPS1G1Y6/novelbuddy-search-overlong-query-playground.png)Evidence: Live check, base commit: searchNovels FAIL
Evidence: Live check, target commit: all four steps PASS
Screenshots
These come from this repo's plugin playground (
npm run dev:start, NovelBuddy selected), with this source's live results on screen. They do not come from the LNReader app: the Android toolchain is not installed on the machine that made this change, so the fix has not been run in the app. The screenshots were captured on commite5c7dd9, before the later review fixes (the word-boundary trim was removed in a later commit), so the search results they show are from that earlier head.Reincarnation Of The Strongest Sword God (Web Novel), which used to fail. Results are on screen:Reproduction (live, 2026-10-15)
The search API's status depends on the query length. The requests below were sent directly to
https://api.novelbuddy.me/titles/search?q=<query>&limit=24&page=1:adata.itemspresent, empty list (218 bytes)asuccess: false, "Search query must be between 1 and 200 characters" (292 bytes)Reincarnation Of The Strongest Sword God (Web Novel)Reincarnation Of The Strongest Sword Goddata.itemswith 24 resultsA 400 has no
data, sobody.data.itemsthrowsCannot read properties of undefined (reading 'items'). That is the error the live check reported on the base commit. The 50-character cap inclampQuerykeeps queries within the limit the API accepts. The API's error message says 200 characters, but the measured limit is 50. The sharedsearchTitleshelper now throws a clearHTTP <status>error instead of the undefined-property error when a response has nodata.items.AI disclosure
This PR was written with AI assistance (Claude). The change, its validation runs and the write-up were AI-driven. No human has reviewed it yet.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
plugins/english/novelbuddy.ts:30- Intent conformance: the required behavior is that search works again. The reported failure isCannot read properties of undefined (reading 'items'), which means the API response no longer hasdata.items. This diff does not change how the response is parsed.parseNovelsstill readsbody.data.itemsat plugins/english/novelbuddy.ts:30, andsearchNovelsstill passes the raw body to it at lines 205-208. The only search change is query trimming (line 204). If the envelope change is the root cause, the same TypeError stays reachable on every search. The commit message and version bump claim a fix for a 400 on long queries, which is a different failure from the one the intent describes. Remedy needs your decision: confirm the actual response shape fromapi.novelbuddy.me/titles/searchand updateparseNovels/searchNovelsto read it, or justify why the 50-char trim addresses theitemserror.plugins/english/novelbuddy.ts:13- The 50-character limit is asserted in a code comment and commit message with no supporting evidence in the repo, and it is not the failure the intent reports.clampQuery(lines 13-20) and both call sites (line 61 in popularNovels, line 204 in searchNovels) are new behavior whose necessity depends on that unverified claim. If the claim is wrong, this is an extra behavior change to the query.plugins/english/novelbuddy.ts:16- clampQuery can split a UTF-16 surrogate pair at index 50.query.slice(0, 50)keeps a lone high surrogate when the 50th code unit starts an emoji or other astral character, and that lone surrogate is then URL-encoded. The word-boundary fallback only helps when there is a space before it.🔧 Fix applied.
6 issues (1 error, 3 warnings, 2 infos) still open:
plugins/english/novelbuddy.ts:30- Intent conformance: the required behavior is that search works again. The reported failure isCannot read properties of undefined (reading 'items'), which means the API response no longer hasdata.items. This diff does not change how the response is parsed.parseNovelsstill readsbody.data.itemsat plugins/english/novelbuddy.ts:30, andsearchNovelsstill passes the raw body to it at lines 205-208. The only search change is query trimming (line 204). If the envelope change is the root cause, the same TypeError stays reachable on every search. The commit message and version bump claim a fix for a 400 on long queries, which is a different failure from the one the intent describes. Remedy needs your decision: confirm the actual response shape fromapi.novelbuddy.me/titles/searchand updateparseNovels/searchNovelsto read it, or justify why the 50-char trim addresses theitemserror.plugins/english/novelbuddy.ts:13- The 50-character limit is asserted in a code comment and commit message with no supporting evidence in the repo, and it is not the failure the intent reports.clampQuery(lines 13-20) and both call sites (line 61 in popularNovels, line 204 in searchNovels) are new behavior whose necessity depends on that unverified claim. If the claim is wrong, this is an extra behavior change to the query.plugins/english/novelbuddy.ts:16- clampQuery can split a UTF-16 surrogate pair at index 50.query.slice(0, 50)keeps a lone high surrogate when the 50th code unit starts an emoji or other astral character, and that lone surrogate is then URL-encoded. The word-boundary fallback only helps when there is a space before it.plugins/english/novelbuddy.ts:78- searchTitles parses the body withresult.json()before checking the response, so a non-JSON error response (e.g. an HTML 403/503 from a block page) throws a SyntaxError and never reaches the newHTTP ${result.status}error. Checkresult.ok/result.statusfirst, or read the body as text and parse it afterwards. Sibling: the same uncheckedjson()pattern in parseChapter's chapters/chapter fetches is pre-existing and out of this change's scope.plugins/english/novelbuddy.ts:19- Simplification: the word-boundary fallback in clampQuery (lastIndexOf(' ')and the.trim()) is not required by the user's stated remedy (keep clampQuery, avoid splitting a surrogate pair, no other behavior changes). It changes what is searched, e.g. a 60-character query is cut back to its last whole word rather than to 50 characters. Remedy: remove the word-boundary branch and keep only the length cap plus the surrogate guard (cut = query.slice(0, 50), drop a trailing high surrogate). This is a product-behavior choice, so it needs the author's decision.plugins/english/novelbuddy.ts:71- The shared searchTitles helper also changes popularNovels (line 71): browse requests with a keyword now go through clampQuery and the HTTP-status error instead of a TypeError on the same malformed response. The user's remedy was scoped to searchNovels ('no other behavior changes'). The change is confined to the error message and the keyword clamp that the user already accepted, so it is noted, not blocking.🔧 Fix applied.
8 issues (1 error, 4 warnings, 3 infos) still open:
plugins/english/novelbuddy.ts:30- Intent conformance: the required behavior is that search works again. The reported failure isCannot read properties of undefined (reading 'items'), which means the API response no longer hasdata.items. This diff does not change how the response is parsed.parseNovelsstill readsbody.data.itemsat plugins/english/novelbuddy.ts:30, andsearchNovelsstill passes the raw body to it at lines 205-208. The only search change is query trimming (line 204). If the envelope change is the root cause, the same TypeError stays reachable on every search. The commit message and version bump claim a fix for a 400 on long queries, which is a different failure from the one the intent describes. Remedy needs your decision: confirm the actual response shape fromapi.novelbuddy.me/titles/searchand updateparseNovels/searchNovelsto read it, or justify why the 50-char trim addresses theitemserror.plugins/english/novelbuddy.ts:13- The 50-character limit is asserted in a code comment and commit message with no supporting evidence in the repo, and it is not the failure the intent reports.clampQuery(lines 13-20) and both call sites (line 61 in popularNovels, line 204 in searchNovels) are new behavior whose necessity depends on that unverified claim. If the claim is wrong, this is an extra behavior change to the query.plugins/english/novelbuddy.ts:16- clampQuery can split a UTF-16 surrogate pair at index 50.query.slice(0, 50)keeps a lone high surrogate when the 50th code unit starts an emoji or other astral character, and that lone surrogate is then URL-encoded. The word-boundary fallback only helps when there is a space before it.plugins/english/novelbuddy.ts:78- searchTitles parses the body withresult.json()before checking the response, so a non-JSON error response (e.g. an HTML 403/503 from a block page) throws a SyntaxError and never reaches the newHTTP ${result.status}error. Checkresult.ok/result.statusfirst, or read the body as text and parse it afterwards. Sibling: the same uncheckedjson()pattern in parseChapter's chapters/chapter fetches is pre-existing and out of this change's scope.plugins/english/novelbuddy.ts:19- Simplification: the word-boundary fallback in clampQuery (lastIndexOf(' ')and the.trim()) is not required by the user's stated remedy (keep clampQuery, avoid splitting a surrogate pair, no other behavior changes). It changes what is searched, e.g. a 60-character query is cut back to its last whole word rather than to 50 characters. Remedy: remove the word-boundary branch and keep only the length cap plus the surrogate guard (cut = query.slice(0, 50), drop a trailing high surrogate). This is a product-behavior choice, so it needs the author's decision.plugins/english/novelbuddy.ts:71- The shared searchTitles helper also changes popularNovels (line 71): browse requests with a keyword now go through clampQuery and the HTTP-status error instead of a TypeError on the same malformed response. The user's remedy was scoped to searchNovels ('no other behavior changes'). The change is confined to the error message and the keyword clamp that the user already accepted, so it is noted, not blocking.plugins/english/novelbuddy.ts:13- Stale commit message: e5c7dd9 ("trim search queries to the 50-character API limit") says queries are trimmed "to a word boundary", but 64ab656 removed the word-boundary branch, so clampQuery (lines 13-20) now only caps at 50 code units and drops a trailing lone high surrogate. The user required the commit message to record the reproduced 400-vs-200 evidence; the message currently describes behavior the code no longer has and omits the 200 side of that evidence. Remedy is rewording the commit message (amend or squash on the branch), not a code change.plugins/english/novelbuddy.ts:77- Error message is misleading when the response is 2xx but has no data.items (e.g. a 200 withdata: null): searchTitles line 77 reportsHTTP 200as the failure, which reads like a status error when the status was fine. The 2xx-without-items path is not the 400 the user asked to surface. Rephrase the message to say the response had no data.items, and keep the status in it. Not a regression: before this change the same response threw a TypeError.✅ **Test** - passed
✅ No issues found.
npm run check:pluginoutput for base commit 49b4727 (temporary copy, removed afterwards): searchNovels FAIL 'Cannot read properties of undefined (reading 'items')'npm run check:plugin -- plugins/english/novelbuddy.tsoutput: all four PASSnpm run check:plugin -- plugins/english/novelbuddyBaseTmp.ts(temporary copy of base commit 49b4727): searchNovels FAIL withCannot read properties of undefined (reading 'items'), others PASSnpm run check:plugin -- plugins/english/novelbuddy.ts(target 64ab656): popularNovels, searchNovels, parseNovel, parseChapter all PASScurlprobes of api.novelbuddy.me/titles/search: 50-char q → 200, 51-char q → 400, 52-char title → 400, 'solo leveling' → 200 with data.items, 49 'a's → 200 emptyPlayground at http://127.0.0.1-mapped localhost:3000 (npx vite --host 127.0.0.2 --port 3000 --strictPort, Chromium with --host-resolver-rules MAP localhost 127.0.0.2): selected NovelBuddy, Search tab, searched 'Reincarnation Of The Strongest Sword God (Web Novel)' → results rendered; screenshot savedPlayground search for 'solo leveling' → results rendered (Solo Leveling: Digispirit., MTL-Solo Leveling, etc.)Playground search for a ~150-char query → results rendered; captured network request q=Reincarnation Of The Strongest Sword God (Web Nove (50-char clamp)Playground search for 49 'a's + emoji + extra → 'No results found', no 'Failed to fetch' errornpm run clean:multisrcand git status check to remove transient generated outputplugins/english/novelbuddy.ts:10- The clampQuery comment states the 400-vs-200 behavior as 'Reproduced against api.novelbuddy.me/titles/search', but no repro, request log, or test is recorded in the repo. The diff also does not change howdata.itemsis parsed, so the reported 'reading items' TypeError is addressed only if the 400 on long queries is the root cause. Needs author confirmation: either attach the repro evidence, or soften the comment to match what was verified.🔧 Fix applied.
1 warning still open:
plugins/english/novelbuddy.ts:10- Commit messages on this branch (e5c7dd9, aa20e12) still say the 400-vs-200 behavior was 'reproduced' and describe a word-boundary trim that 64ab656 removed. The code comment is now corrected, but git history was not rewritten. Amending or squashing these commits is a branch-history decision, so it is left for the author.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.