{"record":{"id":"c563fbd235984db5","repo":"ZhuLinsen/daily_stock_analysis","slug":"field-name-must-not-contain-sensitive-credential","errorCode":null,"errorMessage":"{field_name} must not contain sensitive credentials","messagePattern":"(.+?) must not contain sensitive credentials","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"src/services/decision_signal_service.py","lineNumber":1228,"sourceCode":"                raise ValueError(f\"{field_name} is required\")\n            return None\n        text = sanitize_decision_signal_text(value)\n        if not text:\n            if required:\n                raise ValueError(f\"{field_name} is required\")\n            return None\n        if len(text) > max_length:\n            raise ValueError(f\"{field_name} must be at most {max_length} characters\")\n        return text\n\n    @classmethod\n    def _optional_identity_text(cls, value: Any, field_name: str, *, max_length: int) -> Optional[str]:\n        text = cls._optional_text(value, field_name, max_length=max_length)\n        if text is None:\n            return None\n        sanitized = sanitize_decision_signal_text(text)\n        if any(marker in sanitized for marker in REDACTION_MARKERS):\n            raise ValueError(f\"{field_name} must not contain sensitive credentials\")\n        return text\n\n    @staticmethod\n    def _optional_signal_text(value: Any) -> Optional[str]:\n        if value is None:\n            return None\n        if isinstance(value, (dict, list)):\n            return json.dumps(sanitize_decision_signal_payload(value), ensure_ascii=False, sort_keys=True)\n        text = sanitize_decision_signal_text(value)\n        return text or None\n\n    @staticmethod\n    def _optional_float(value: Any, field_name: str) -> Optional[float]:\n        if value in (None, \"\"):\n            return None\n        try:\n            return float(value)\n        except (TypeError, ValueError) as exc:","sourceCodeStart":1210,"sourceCodeEnd":1246,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/src/services/decision_signal_service.py#L1210-L1246","documentation":"ValueError from DecisionSignalService._optional_identity_text (src/services/decision_signal_service.py:1228): optional identity-ish fields (e.g. ids/labels) are sanitized and then scanned for REDACTION_MARKERS; if any marker substring appears, the value is presumed to contain sensitive credentials and is rejected. This is a data-leak guard preventing tokens/keys from being persisted into decision-signal records.","triggerScenarios":"Passing a value that contains a redaction marker substring — typically text that itself looks like or contains credential material: 'sk-...', 'Bearer ...', 'api_key=...', 'password=', token fragments, or content already tagged by the sanitizer with a redaction placeholder like '[REDACTED]'. Because the check is substring-based, innocent text embedding a marker (e.g. a note quoting a log line 'Authorization: Bearer ***') also trips it.","commonSituations":"Debug payloads copy-pasting auth headers or .env fragments into a label field; upstream error messages that embed redacted secrets ('api_key=REDACTED') forwarded verbatim; over-broad marker matching flagging words that merely contain a marker substring; users pasting connector URLs with embedded tokens.","solutions":["Strip credential-shaped content before sending: never forward raw headers, tokens, or redacted log lines into identity fields.","If the marker hit is a false positive from innocuous text, rephrase the value to avoid the marker substring, and report the over-match to maintainers.","Route structured secrets to dedicated secret storage (devkey/registry), never decision-signal fields.","Add a pre-flight scan of payload text fields for marker substrings client-side."],"exampleFix":"# before\nlabel = f\"retry-of-{failed_request_headers}\"  # contains 'Bearer eyJ...' → ValueError\nservice.create_signal({..., \"label\": label})\n\n# after\nlabel = f\"retry-of-run-{run_id}\"\nservice.create_signal({..., \"label\": label})","handlingStrategy":"validation","validationCode":"from src.services.decision_signal_service import REDACTION_MARKERS\ndef clean_of_markers(text: str) -> str:\n    return text if not any(m in text for m in REDACTION_MARKERS) else ''\nfor field in ('label', 'trigger_source'):\n    if field in payload and not clean_of_markers(payload[field]):\n        del payload[field]  # drop credential-tainted values before the call","typeGuard":"def is_marker_free(text: str | None) -> bool:\n    return text is None or not any(marker in str(text) for marker in REDACTION_MARKERS)","tryCatchPattern":null,"preventionTips":["Never forward auth headers, tokens, or redacted log lines into signal text fields.","Keep secrets in dedicated secret storage (devkey), reference by name only.","If a marker false-positives on legitimate text, rephrase and report it to maintainers."],"tags":["decision-signal","security","secrets","sanitization","validation"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}