
WaterCrawl credential validation leaks JSONDecodeError for non-JSON error responses
快速结论:当 WaterCrawl 的认证端点返回非 JSON 格式的错误响应体(例如 HTTP 401 并返回纯文本 “Not JSON”)时,Dify 中的 WatercrawlAuth.validate_credentials() 会因未处理的 JSONDecodeError 而抛出原始 Python 异常,而非返回友好的认证错误信息。优先排查 api/services/auth/watercrawl/watercrawl.py 中 _handle_error 方法的 JSON 解析逻辑,并考虑添加 try/except 回退机制。
问题场景
用户在使用 Dify 的数据源功能,配置并验证 WaterCrawl 凭据时触发。具体操作是在 Dify 中为 WaterCrawl 数据源设置认证凭据,WaterCrawl 服务端返回了非 JSON 格式的错误响应(如 HTTP 401 状态码,响应体为纯文本)。
报错原文
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
或 Python 中对应的 JSONDecodeError 异常堆栈,该异常掩盖了实际的 HTTP 状态码和错误信息。
原因分析
可能原因:Dify 的 WaterCrawl 认证流程中,_handle_error() 方法(位于 api/services/auth/watercrawl/watercrawl.py 第 38-46 行)在解析非 2xx 状态码的响应时,使用了 response.json() 或 json.loads(response.text) 方式解析响应体。如果响应体不是有效的 JSON 格式(例如纯文本 “Not JSON”),则会直接抛出未捕获的 JSONDecodeError,而不是返回包含 HTTP 状态码的可读错误消息。
环境排查
- 确认 Dify 的版本为
main branch at b6b9165d或包含该 commit 的版本。 - 确认环境是 Dify Cloud 或 Self Hosted(Source 方式部署)。
- 检查 WaterCrawl API 服务端响应头中
Content-Type是否为application/json(否则可能导致非 JSON 响应体)。 - 对比兄弟服务 Firecrawl 的认证实现,它已包含对非 JSON 响应体的回退处理。
解决步骤
- 定位 Dify 源代码中的
api/services/auth/watercrawl/watercrawl.py文件。 - 找到
_handle_error方法,该方法对 HTTP 状态码分别进行判断:- 对状态码 402、409、500 的处理中,调用了
response.json()(第 40 行)。 - 对其他非预期状态码的处理中,调用了
json.loads(response.text)(第 44 行)。
- 对状态码 402、409、500 的处理中,调用了
- 将这两个 JSON 解析调用包裹在 try/except 块中,捕获
JSONDecodeError或通用的Exception,并在异常时回退到使用原始响应文本作为错误信息。可优先尝试以下修复逻辑:def _handle_error(self, response): if response.status_code in {402, 409, 500}: try: error_message = response.json().get("error", "Unknown error occurred") except Exception: error_message = response.text or "Unknown error occurred" raise Exception(f"Failed to authorize. Status code: {response.status_code}. Error: {error_message}") else: if response.text: try: error_message = json.loads(response.text).get("error", "Unknown error occurred") except (json.JSONDecodeError, ValueError): error_message = response.text raise Exception(f"Failed to authorize. Status code: {response.status_code}. Error: {error_message}") raise Exception(f"Unexpected error occurred while trying to authorize. Status code: {response.status_code}") - 保存修改并重新部署 Dify 实例。
验证方法
重新触发 WaterCrawl 凭据验证,确保 WaterCrawl 服务端返回非 JSON 格式的 HTTP 错误响应(例如 401 状态码 + 纯文本 “Not JSON”)。此时不再抛出原始的 JSONDecodeError,而是显示包含 HTTP 状态码和原始响应文本的友好错误信息,例如:“Failed to authorize. Status code: 401. Error: Not JSON”。



