crawl4ai version
0.9.0 (Docker server). Also present on develop — see below.
Summary
In the Docker playground (/playground), entering any Advanced Config (CrawlerRunConfig or BrowserConfig) and clicking Run immediately fails with:
{ "error": "{\"detail\":\"type must be 'CrawlerRunConfig' or 'BrowserConfig'\"}" }
The playground's client JS calls POST /config/dump with only { code }, but the 0.9.0 endpoint requires a type field, so every custom config is rejected with HTTP 400. There is no way to use a custom CrawlerRunConfig/BrowserConfig from the playground.
Steps to reproduce
- Run the 0.9.0 Docker server with a token set (so the UI is reachable).
- Open
/playground and expand ▶ Advanced Config — it defaults to CrawlerRunConfig(stream=True, cache_mode=CacheMode.BYPASS).
- Click Run.
Result: the Response panel shows type must be 'CrawlerRunConfig' or 'BrowserConfig'. Reproduces for stream=True and stream=False, and for the BrowserConfig template.
Root cause
Client omits type — deploy/docker/static/playground/index.html, pyConfigToJson():
const res = await fetch('/config/dump', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code }), // <-- no `type`
});
Server requires type — deploy/docker/server.py, _config_from_json() (called by POST /config/dump):
config_type = data.get("type")
if config_type == "CrawlerRunConfig":
...
elif config_type == "BrowserConfig":
...
else:
raise ValueError("type must be 'CrawlerRunConfig' or 'BrowserConfig'")
The UI already knows the type — it is selected in the #cfg-type <select> (CrawlerRunConfig / BrowserConfig) that drives the config templates — it simply isn't sent in the request body.
Evidence
# omitting type -> HTTP 400
$ curl -sX POST .../config/dump -H 'Content-Type: application/json' \
-d '{"code":"CrawlerRunConfig(stream=False, cache_mode=CacheMode.BYPASS)"}'
{"detail":"type must be 'CrawlerRunConfig' or 'BrowserConfig'"}
# including type -> HTTP 200
$ curl -sX POST .../config/dump -H 'Content-Type: application/json' \
-d '{"type":"CrawlerRunConfig","code":"CrawlerRunConfig(stream=False, cache_mode=CacheMode.BYPASS)"}'
{"type":"CrawlerRunConfig","params":{ ... }}
Fix (one line)
Send the selected type from #cfg-type in pyConfigToJson():
const res = await fetch('/config/dump', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ code }),
+ body: JSON.stringify({ type: document.getElementById('cfg-type').value, code }),
});
Verified: with this change /config/dump returns 200, and the subsequent POST /crawl with the resulting crawler_config returns a normal batch result ("success": true).
Still present on develop
The develop branch (which has the merged auth-gate fix #2039) still omits type in the same call — it uses authFetch('/config/dump', { ... body: JSON.stringify({ code }) }) (~line 569) — so this bug is not fixed there.
Secondary symptom (same broken path, FYI)
Because the 400 is caught and the fallback sets advConfig = { crawler_config: { stream: true } }, while shouldUseStream() checks crawler_config.params.stream (different nesting), the default stream=True template makes the client send a streaming request but parse it as batch. The server then returns NDJSON ({…result…}\n{"status":"completed"}) and response.json() throws SyntaxError: Unexpected non-whitespace character after JSON … (line 2 column 1). Fixing the type omission above resolves the custom-config 400; the shouldUseStream nesting mismatch looks like a related follow-up.
crawl4ai version
0.9.0 (Docker server). Also present on
develop— see below.Summary
In the Docker playground (
/playground), entering any Advanced Config (CrawlerRunConfig or BrowserConfig) and clicking Run immediately fails with:{ "error": "{\"detail\":\"type must be 'CrawlerRunConfig' or 'BrowserConfig'\"}" }The playground's client JS calls
POST /config/dumpwith only{ code }, but the 0.9.0 endpoint requires atypefield, so every custom config is rejected with HTTP 400. There is no way to use a customCrawlerRunConfig/BrowserConfigfrom the playground.Steps to reproduce
/playgroundand expand ▶ Advanced Config — it defaults toCrawlerRunConfig(stream=True, cache_mode=CacheMode.BYPASS).Result: the Response panel shows
type must be 'CrawlerRunConfig' or 'BrowserConfig'. Reproduces forstream=Trueandstream=False, and for theBrowserConfigtemplate.Root cause
Client omits
type—deploy/docker/static/playground/index.html,pyConfigToJson():Server requires
type—deploy/docker/server.py,_config_from_json()(called byPOST /config/dump):The UI already knows the type — it is selected in the
#cfg-type<select>(CrawlerRunConfig / BrowserConfig) that drives the config templates — it simply isn't sent in the request body.Evidence
Fix (one line)
Send the selected type from
#cfg-typeinpyConfigToJson():const res = await fetch('/config/dump', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ code }), + body: JSON.stringify({ type: document.getElementById('cfg-type').value, code }), });Verified: with this change
/config/dumpreturns 200, and the subsequentPOST /crawlwith the resultingcrawler_configreturns a normal batch result ("success": true).Still present on
developThe
developbranch (which has the merged auth-gate fix #2039) still omitstypein the same call — it usesauthFetch('/config/dump', { ... body: JSON.stringify({ code }) })(~line 569) — so this bug is not fixed there.Secondary symptom (same broken path, FYI)
Because the 400 is caught and the fallback sets
advConfig = { crawler_config: { stream: true } }, whileshouldUseStream()checkscrawler_config.params.stream(different nesting), the defaultstream=Truetemplate makes the client send a streaming request but parse it as batch. The server then returns NDJSON ({…result…}\n{"status":"completed"}) andresponse.json()throwsSyntaxError: Unexpected non-whitespace character after JSON … (line 2 column 1). Fixing thetypeomission above resolves the custom-config 400; theshouldUseStreamnesting mismatch looks like a related follow-up.