bytedance/deer-flow · error · HTTPException
Cannot set extra config key '{key}' to masked value '***'; p
Error message
Cannot set extra config key '{key}' to masked value '***'; provide a real value. What it means
400 raised when an MCP configuration update sends the literal masked value '***' for a sensitive extra-config key that does not already exist in the stored configuration. GET responses mask sensitive values; when updating, the server preserves existing values for masked round-trips, but a masked value with no stored original cannot be resolved, so it is rejected.
Source
Thrown at backend/app/gateway/routers/mcp.py:461
def _is_sensitive_extra_key(key: str) -> bool:
return bool(_SENSITIVE_EXTRA_KEY_RE.search(_normalize_config_key(key)))
def _mask_sensitive_extra_value(value: Any) -> Any:
if isinstance(value, dict):
return {key: _MASKED_VALUE if _is_sensitive_extra_key(str(key)) else _mask_sensitive_extra_value(nested) for key, nested in value.items()}
if isinstance(value, list):
return [_mask_sensitive_extra_value(item) for item in value]
return value
def _merge_extra_value_preserving_masked(key: str, incoming_value: Any, existing_value: Any, *, existing_present: bool) -> Any:
if incoming_value == _MASKED_VALUE and _is_sensitive_extra_key(key):
if existing_present:
return existing_value
raise HTTPException(
status_code=400,
detail=f"Cannot set extra config key '{key}' to masked value '***'; provide a real value.",
)
if isinstance(incoming_value, dict) and isinstance(existing_value, dict):
merged: dict[str, Any] = {}
for nested_key, nested_value in incoming_value.items():
nested_present = nested_key in existing_value
merged[nested_key] = _merge_extra_value_preserving_masked(
str(nested_key),
nested_value,
existing_value.get(nested_key),
existing_present=nested_present,
)
return merged
if isinstance(incoming_value, list) and isinstance(existing_value, list) and len(incoming_value) == len(existing_value):
return [_merge_extra_value_preserving_masked(key, nested_value, existing_value[index], existing_present=True) for index, nested_value in enumerate(incoming_value)]View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Send a real secret value instead of '***' for any sensitive key that is newly added
- Keep an unmasked source of truth (secret manager or local file) and merge masked GET output with real values before submitting
- When round-tripping an existing server's config, leave sensitive keys with '***' only if they already exist in stored config (then they are preserved)
Example fix
# before
extra: {"api_token": "***"} # new key, masked value -> 400
# after
extra: {"api_token": "sk-real-secret-from-vault"} Defensive patterns
Strategy: validation
Validate before calling
function assertNoMaskedNewKeys(incomingExtra: Record<string, unknown>, existingExtra: Record<string, unknown> | undefined) { for (const [k, v] of Object.entries(incomingExtra)) { if (v === '***' && !(existingExtra && k in existingExtra)) throw new Error(`provide a real value for new key ${k}`); if (typeof v === 'object' && v !== null) assertNoMaskedNewKeys(v as any, existingExtra?.[k] as any); } } Type guard
function isMaskedSentinel(v: unknown): v is '***' { return v === '***'; } Try / catch
try { await putMcpConfig(payload); } catch (e) { if (e.status === 400 && /masked value/.test(e.detail)) { /* replace *** for the named key with the real secret and retry once */ } throw e; } Prevention
- Never build payloads by copying masked GET responses for new entries
- Inject real secrets from a vault at submit time
- Round-trip masked values only for keys already present in stored config
When it happens
Trigger: PUT to the MCP config endpoint where extra config contains {'api_token': '***'} for a key that was never set before; constructing a config payload by copying a masked GET response for a brand-new server entry; adding a new sensitive nested key whose value came from another server's masked response.
Common situations: Config-as-code workflows that fetch the live (masked) config and re-submit it as a template for new servers; UI edits that pre-fill masked placeholders into create forms.
Related errors
- Cannot set env key '{k}' to masked value '***'; provide a re
- Cannot set header '{k}' to masked value '***'; provide a rea
- MCP server '{server_name}' with stdio transport requires a c
- Failed to load MCP configuration
- Failed to update MCP configuration
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/c90529c437429697.
Report an issue: GitHub.