
WaterCrawl crawler error responses can leak JSONDecodeError
快速结论:当 WaterCrawl 爬虫 API 返回非 JSON 格式的 401/403/4xx 响应体时(如 HTML 页面),异常处理类会因无保护的 response.json() 调用抛出 JSONDecodeError,掩盖原始业务异常。优先排查 WaterCrawl 配置或中间代理是否返回了 text/html 类型的错误响应。
问题场景
在 Dify 中配置 WaterCrawl 网站抓取功能(Self Hosted Source / Docker),当 WaterCrawl API 或代理网关返回状态码 401、403 或 4xx 且响应体为 HTML/纯文本而非 JSON 时,触发 JSONDecodeError。
报错原文
JSONDecodeError: Expecting value: line 1 column 1 (char 0)
原因分析
可能原因:
WaterCrawlBadRequestError.__init__(以及继承该类的WaterCrawlAuthenticationError和WaterCrawlPermissionError)在exceptions.py第 13 行无条件调用response.json(),没有处理 JSON 解析异常。client.py第 124 行的response.json() or {}同样缺少错误保护。- 当 WaterCrawl、代理或上游网关返回非 JSON 体的 4xx 错误时,预期的 WaterCrawl 异常会被低层
JSONDecodeError替换。
环境排查
- 确认 Dify 版本是否为当前
main分支(通过代码检查发现问题)。 - 检查 WaterCrawl API 配置是否正确。
- 检查是否有中间代理(如 Nginx、反向代理)返回 HTML 页面而非 JSON。
解决步骤
- 优先尝试:在
exceptions.py中修改WaterCrawlBadRequestError类的__init__方法,为response.json()添加try/except,捕获ValueError和Exception,回退使用response.text:
class WaterCrawlBadRequestError(WaterCrawlError):
def __init__(self, response):
self.status_code = response.status_code
self.response = response
try:
data = response.json()
except (ValueError, Exception):
data = {}
self.message = data.get("message", response.text or "Unknown error occurred")
self.errors = data.get("errors", {})
super().__init__(self.message)
- 在
client.py第 124 行,将return response.json() or {}用try/except包裹,回退到空字典或抛出清晰的错误信息。
验证方法
模拟一个返回 401 状态码且响应体为 HTML 格式的请求,确认触发时抛出的是 WaterCrawlAuthenticationError 而非 JSONDecodeError,且异常信息为响应文本或默认错误消息。



