Self Checks
RAGFlow workspace code commit ID
main @ 326893811 (also reproducible on 0a8f28ff3 and any prior v0.26.x).
RAGFlow image version
v0.26.4 (also reproducible on the current dev image).
Other environment information
- Provider:
VolcEngine (factory name), aka ByteDance Volcengine Ark (https://ark.cn-beijing.volces.com/api/v3)
- Affected classes:
VolcEngineChat (rag/llm/chat_model.py:965), VolcEngineCV (rag/llm/cv_model.py:614), VolcEngineEmbed (rag/llm/embedding_model.py:1086)
Actual behavior
The VolcEngine/Ark provider in rag/llm/ parses its API key as JSON, looking for ark_api_key, ep_id, and endpoint_id. The current code has a partial try/except around the parse:
# rag/llm/chat_model.py:975 (also in cv_model.py:621 and embedding_model.py:1100)
try:
ark_api_key = json.loads(key).get("ark_api_key", "")
model_name = json.loads(key).get("ep_id", "") + json.loads(key).get("endpoint_id", "")
super().__init__(ark_api_key, model_name, base_url, **kwargs)
except JSONDecodeError:
super().__init__(key, model_name, base_url, **kwargs)
except JSONDecodeError only catches the case where the string fails to parse as JSON. It does NOT catch AttributeError from .get(...) when the parsed JSON is not an object — for example:
key = '[1, 2, 3]' parses to a list → .get("ark_api_key", "") raises AttributeError: 'list' object has no attribute 'get'
key = '"a plain string"' parses to a string → same AttributeError
key = 'null' parses to None → same AttributeError
key = '42' parses to int → same AttributeError
key = 'true' parses to bool → same AttributeError
key = '[1, 2]' (a JSON array) → same AttributeError
In every case the call site raises an unhandled AttributeError that bubbles up as a 500 in the API and a stack trace in the server log. This is the same class of bug that PR #17215 fixed for Azure, PR #17377 fixed for Bedrock, and PR #17390 fixed for BaiduYiyan. The VolcEngine call sites are the only remaining unfixed LLM-provider JSON-decode sites in rag/llm/.
Expected behavior
A user pasting any non-VolcEngine-shaped key (a plain API key, a JSON list, a JSON number, a malformed JSON object) should get a clear, actionable error at provider-init time, not a 500. The existing fallback for plain-string keys (use the raw key as ark_api_key) is reasonable and should be preserved. A JSON non-object should raise the same ModelException family the other provider helpers raise, pointing the user at the required schema.
Steps to reproduce
- Start RAGFlow
v0.26.4 (any deployment).
- Try to add a VolcEngine model provider via the admin UI (or
POST /api/v1/llm/factories).
- Paste any of these into the API key field:
- A plain AWS-style key like
"AKLA..." — works (falls through to the JSONDecodeError branch and uses the raw string).
- A JSON array like
["a", "b"] — crashes with AttributeError: 'list' object has no attribute 'get'.
- A JSON number like
42 — same crash.
- A JSON string like
"a plain string" (with quotes) — same crash.
- A JSON null
null — same crash.
- The server log shows an unhandled
AttributeError. The admin UI shows a generic 500 with no actionable hint.
Expected error surface
After the fix, a JSON non-object should raise the same clear error as the other provider helpers (e.g. ModelException(retryable=False) with a message like: "VolcEngine requires a JSON object with 'ark_api_key' and ('ep_id' or 'endpoint_id'); got <type>").
The plain-string-key fallback should be preserved (the existing partial handler is correct for that case).
Additional information
Affected files and line numbers (in commit 326893811):
| File |
Class |
Lines |
rag/llm/chat_model.py |
VolcEngineChat |
975-980 |
rag/llm/cv_model.py |
VolcEngineCV |
621-627 |
rag/llm/embedding_model.py |
VolcEngineEmbed |
1100-1106 |
All three sites use the same try/except JSONDecodeError pattern and have the same bug shape. The fix should be a single helper in rag/llm/key_utils.py (following the established pattern for _resolve_bedrock_credentials and _resolve_qianfan_credentials) wired into all three call sites, with regression tests covering:
- Plain string key →
ark_api_key = key, model_name derived from passed arg (preserves existing fallback)
- JSON dict with all fields →
ark_api_key = cfg["ark_api_key"], model_name = cfg["ep_id"] + cfg["endpoint_id"] (preserves existing happy path)
- JSON dict missing some fields →
cfg.get(k, "") defaults (preserves existing tolerance)
- JSON list, number, string, null, bool →
ModelException (the new fix)
- Bad JSON string →
ModelException (the new fix) — currently the JSONDecodeError branch silently uses the raw string, which is the existing partial fix; this PR can keep that behavior or upgrade it to ModelException for consistency with the other helpers
- Helper propagates the right fields to the call site so each model type (chat / cv / embed) gets exactly what it needs
A PR fixing this is in progress.
Self Checks
RAGFlow workspace code commit ID
main@326893811(also reproducible on0a8f28ff3and any priorv0.26.x).RAGFlow image version
v0.26.4(also reproducible on the current dev image).Other environment information
VolcEngine(factory name), aka ByteDance Volcengine Ark (https://ark.cn-beijing.volces.com/api/v3)VolcEngineChat(rag/llm/chat_model.py:965),VolcEngineCV(rag/llm/cv_model.py:614),VolcEngineEmbed(rag/llm/embedding_model.py:1086)Actual behavior
The VolcEngine/Ark provider in
rag/llm/parses its API key as JSON, looking forark_api_key,ep_id, andendpoint_id. The current code has a partial try/except around the parse:except JSONDecodeErroronly catches the case where the string fails to parse as JSON. It does NOT catchAttributeErrorfrom.get(...)when the parsed JSON is not an object — for example:key = '[1, 2, 3]'parses to a list →.get("ark_api_key", "")raisesAttributeError: 'list' object has no attribute 'get'key = '"a plain string"'parses to a string → sameAttributeErrorkey = 'null'parses toNone→ sameAttributeErrorkey = '42'parses toint→ sameAttributeErrorkey = 'true'parses tobool→ sameAttributeErrorkey = '[1, 2]'(a JSON array) → sameAttributeErrorIn every case the call site raises an unhandled
AttributeErrorthat bubbles up as a 500 in the API and a stack trace in the server log. This is the same class of bug that PR #17215 fixed for Azure, PR #17377 fixed for Bedrock, and PR #17390 fixed for BaiduYiyan. The VolcEngine call sites are the only remaining unfixed LLM-provider JSON-decode sites inrag/llm/.Expected behavior
A user pasting any non-VolcEngine-shaped key (a plain API key, a JSON list, a JSON number, a malformed JSON object) should get a clear, actionable error at provider-init time, not a 500. The existing fallback for plain-string keys (use the raw key as
ark_api_key) is reasonable and should be preserved. A JSON non-object should raise the sameModelExceptionfamily the other provider helpers raise, pointing the user at the required schema.Steps to reproduce
v0.26.4(any deployment).POST /api/v1/llm/factories)."AKLA..."— works (falls through to theJSONDecodeErrorbranch and uses the raw string).["a", "b"]— crashes withAttributeError: 'list' object has no attribute 'get'.42— same crash."a plain string"(with quotes) — same crash.null— same crash.AttributeError. The admin UI shows a generic 500 with no actionable hint.Expected error surface
After the fix, a JSON non-object should raise the same clear error as the other provider helpers (e.g.
ModelException(retryable=False)with a message like:"VolcEngine requires a JSON object with 'ark_api_key' and ('ep_id' or 'endpoint_id'); got <type>").The plain-string-key fallback should be preserved (the existing partial handler is correct for that case).
Additional information
Affected files and line numbers (in commit
326893811):rag/llm/chat_model.pyVolcEngineChatrag/llm/cv_model.pyVolcEngineCVrag/llm/embedding_model.pyVolcEngineEmbedAll three sites use the same
try/except JSONDecodeErrorpattern and have the same bug shape. The fix should be a single helper inrag/llm/key_utils.py(following the established pattern for_resolve_bedrock_credentialsand_resolve_qianfan_credentials) wired into all three call sites, with regression tests covering:ark_api_key = key,model_namederived from passed arg (preserves existing fallback)ark_api_key = cfg["ark_api_key"],model_name = cfg["ep_id"] + cfg["endpoint_id"](preserves existing happy path)cfg.get(k, "")defaults (preserves existing tolerance)ModelException(the new fix)ModelException(the new fix) — currently theJSONDecodeErrorbranch silently uses the raw string, which is the existing partial fix; this PR can keep that behavior or upgrade it toModelExceptionfor consistency with the other helpersA PR fixing this is in progress.