{"record":{"id":"dab0a3a392d2f1d8","repo":"bytedance/deer-flow","slug":"openviking-failure-policy-read-must-be-fail-open","errorCode":null,"errorMessage":"OpenViking failure_policy.read must be 'fail_open' or 'raise'","messagePattern":"OpenViking failure_policy\\.read must be 'fail_open' or 'raise'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/packages/harness/deerflow/agents/memory/backends/openviking/config.py","lineNumber":139,"sourceCode":"            raise ValueError(\"OpenViking default_peer_id must start with a lowercase letter or digit and contain at most 64 lowercase letters, digits, '_' or '-'\")\n        if self.default_peer_id.startswith(GENERATED_PEER_PREFIX):\n            raise ValueError(f\"OpenViking default_peer_id must not start with the reserved prefix {GENERATED_PEER_PREFIX!r}\")\n        if not isfinite(self.timeout_seconds) or self.timeout_seconds <= 0:\n            raise ValueError(\"OpenViking timeout_seconds must be a finite value > 0\")\n        if not 1 <= self.search_top_k <= 100:\n            raise ValueError(\"OpenViking retrieval.top_k must be between 1 and 100\")\n        if self.score_threshold is not None and (not isfinite(self.score_threshold) or not 0 <= self.score_threshold <= 1):\n            raise ValueError(\"OpenViking retrieval.score_threshold must be a finite value between 0 and 1\")\n        if not 256 <= self.max_injection_chars <= 100_000:\n            raise ValueError(\"OpenViking retrieval.max_injection_chars must be between 256 and 100000\")\n        if self.content_mode not in {\"auto\", \"abstract\", \"overview\", \"read\"}:\n            raise ValueError(\"OpenViking retrieval.content_mode must be auto, abstract, overview, or read\")\n        if not self.injection_query:\n            raise ValueError(\"OpenViking retrieval.injection_query must not be empty\")\n        if self.startup_policy not in {\"fail_fast\", \"warn\"}:\n            raise ValueError(\"OpenViking startup_policy must be 'fail_fast' or 'warn'\")\n        if self.read_failure_policy not in {\"fail_open\", \"raise\"}:\n            raise ValueError(\"OpenViking failure_policy.read must be 'fail_open' or 'raise'\")\n        if self.write_failure_policy not in {\"log_and_drop\", \"raise\"}:\n            raise ValueError(\"OpenViking failure_policy.write must be 'log_and_drop' or 'raise'\")\n        if not 16 <= self.max_seen_message_ids <= 10_000:\n            raise ValueError(\"OpenViking max_seen_message_ids must be between 16 and 10000\")\n\n\ndef is_safe_peer_id(value: str) -> bool:\n    \"\"\"Return whether *value* is valid for an OpenViking actor peer.\"\"\"\n\n    return _SAFE_PEER_RE.fullmatch(value) is not None\n\n\ndef _mapping(value: Any, name: str) -> dict[str, Any]:\n    if value is None:\n        return {}\n    if not isinstance(value, dict):\n        raise ValueError(f\"OpenViking {name} must be a mapping\")\n    return dict(value)","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/packages/harness/deerflow/agents/memory/backends/openviking/config.py#L121-L157","documentation":"OpenVikingConfig._validate() rejects memory.backend_config.failure_policy.read values outside {'fail_open','raise'}. read_failure_policy decides whether a failed recall (memory injection) returns empty context (fail_open, the default) or propagates the error into the agent run (raise). The value is lowercased before validation.","triggerScenarios":"Setting memory.backend_config.failure_policy.read to anything other than 'fail_open' or 'raise' — e.g. 'fail_closed' (the honcho backend's term), 'log', 'ignore'. Raised during OpenVikingConfig.from_backend_config -> _validate() at manager construction.","commonSituations":"Porting a honcho backend_config block to OpenViking and keeping 'fail_closed'; typo like 'fail-open' or 'failopen'; believing there is a silent 'log' mode.","solutions":["Set memory.backend_config.failure_policy.read: fail_open (default; recall failures yield empty memory) or raise (recall failures propagate)","Remove the failure_policy.read key to accept the fail_open default","Restart the Gateway so the corrected config is reloaded"],"exampleFix":"# before (config.yaml)\nmemory:\n  backend_config:\n    failure_policy:\n      read: fail_closed   # honcho term, invalid here\n\n# after\nmemory:\n  backend_config:\n    failure_policy:\n      read: fail_open","handlingStrategy":"validation","validationCode":"allowed = {\"fail_open\", \"raise\"}\nval = str((raw_backend_config.get(\"failure_policy\") or {}).get(\"read\", \"fail_open\")).strip().lower()\nassert val in allowed, f\"failure_policy.read must be one of {sorted(allowed)}, got {val!r}\"","typeGuard":"def is_valid_read_policy(value: object) -> bool:\n    return isinstance(value, str) and value.strip().lower() in {\"fail_open\", \"raise\"}","tryCatchPattern":"try:\n    OpenVikingMemoryManager.from_config(backend_config)\nexcept ValueError as exc:\n    log_config_error(exc); fix_and_retry()","preventionTips":["Do not copy honcho's 'fail_closed' vocabulary into OpenViking configs","Validate the whole failure_policy mapping in a config preflight","Omit failure_policy.read to use the fail_open default"],"tags":["openviking","config","validation","failure-policy"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}