fix: improve error handling for Cloudflare-protected clone sources
CI / check (push) Successful in 26s
CI / release (push) Skipped
CI / deploy (push) Successful in 54s

- Detect HTML responses from FlareSolverr and throw descriptive error
  instead of letting JSON.parse fail with cryptic 'Unexpected token' error
- Add try/catch to clone/route.ts GET handler to return 502 with
  clear message instead of Internal Server Error 500
- Add FLARESOLVERR_URL to .env
This commit is contained in:
openhands committed 2026-08-04 19:21:31 +02:00
1 parent 0abcead359
commit 1fd6f7146b
2 files changed
+25 -6

No files matched your search

+20 -6
View File
@@ -33,7 +33,14 @@ export const GET = withAdmin(
// GET ?source=<id>&action=clonable → all not-yet-present classnames (for "clone all") // GET ?source=<id>&action=clonable → all not-yet-present classnames (for "clone all")
if (sp.get("action") === "clonable") { if (sp.get("action") === "clonable") {
return apiOk({ classnames: await getClonableClassnames(source) }); try {
return apiOk({ classnames: await getClonableClassnames(source) });
} catch (err) {
return apiError(
`Failed to fetch source data: ${(err as Error).message}`,
502,
);
}
} }
const search = sp.get("search") || ""; const search = sp.get("search") || "";
@@ -48,12 +55,19 @@ export const GET = withAdmin(
? filterParam ? filterParam
: "all"; : "all";
const [listResult, stats] = await Promise.all([ try {
getCloneList({ source, search, page, perPage, filter }), const [listResult, stats] = await Promise.all([
getCloneStats(source), getCloneList({ source, search, page, perPage, filter }),
]); getCloneStats(source),
]);
return apiOk({ items: listResult.items, meta: listResult.meta, stats }); return apiOk({ items: listResult.items, meta: listResult.meta, stats });
} catch (err) {
return apiError(
`Failed to fetch source data: ${(err as Error).message}`,
502,
);
}
}, },
); );
+5
View File
@@ -106,6 +106,11 @@ export async function fetchSourceFurnidata(
} catch { } catch {
body = await fetchWithFlareSolver(url); body = await fetchWithFlareSolver(url);
} }
if (body.trimStart().startsWith("<")) {
throw new Error(
`Source ${url} is behind a Cloudflare challenge that could not be bypassed. Start FlareSolverr and check its logs.`,
);
}
let list: SourceFurni[]; let list: SourceFurni[];
try { try {
const json = JSON.parse(body); const json = JSON.parse(body);