ZhuLinsen/daily_stock_analysis · error · ValueError

{field_name} is required

Error message

{field_name} is required

What it means

ValueError from DecisionSignalService._public_text (src/services/decision_signal_service.py:1210) when required=True and the raw value is None. Required public-text fields (trigger_source is the main one) must be present; this is the None branch — contrast with the line-1215 branch where the value exists but sanitizes to empty. Same message, two distinct causes in the same helper.

Source

Thrown at src/services/decision_signal_service.py:1210

    def _optional_text(value: Any, field_name: str, *, max_length: int) -> Optional[str]:
        if value is None:
            return None
        text = str(value).strip()
        if not text:
            return None
        if len(text) > max_length:
            raise ValueError(f"{field_name} must be at most {max_length} characters")
        return text

    @classmethod
    def _optional_public_text(cls, value: Any, field_name: str, *, max_length: int) -> Optional[str]:
        return cls._public_text(value, field_name, max_length=max_length, required=False)

    @staticmethod
    def _public_text(value: Any, field_name: str, *, max_length: int, required: bool) -> Optional[str]:
        if value is None:
            if required:
                raise ValueError(f"{field_name} is required")
            return None
        text = sanitize_decision_signal_text(value)
        if not text:
            if required:
                raise ValueError(f"{field_name} is required")
            return None
        if len(text) > max_length:
            raise ValueError(f"{field_name} must be at most {max_length} characters")
        return text

    @classmethod
    def _optional_identity_text(cls, value: Any, field_name: str, *, max_length: int) -> Optional[str]:
        text = cls._optional_text(value, field_name, max_length=max_length)
        if text is None:
            return None
        sanitized = sanitize_decision_signal_text(text)
        if any(marker in sanitized for marker in REDACTION_MARKERS):
            raise ValueError(f"{field_name} must not contain sensitive credentials")

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Always include a concrete non-empty trigger_source (or the relevant required field) in create payloads.
  2. Fix payload builders that filter out falsy values — use `if v is not None` instead of `if v`.
  3. setdefault a sensible constant per producer before the service call.
  4. Add client-side schema validation marking the field required.

Example fix

# before
payload = {k: v for k, v in raw.items() if v}  # drops trigger_source when falsy → ValueError
service.create_signal(payload)

# after
payload = {k: v for k, v in raw.items() if v is not None}
payload.setdefault("trigger_source", "manual")
service.create_signal(payload)
Defensive patterns

Strategy: validation

Validate before calling

if not payload.get('trigger_source'):
    raise ValueError('trigger_source is required — include a non-empty value')

Type guard

def payload_has_required_text(payload: dict, field: str) -> bool:
    return payload.get(field) is not None and str(payload[field]).strip() != ''

Prevention

When it happens

Trigger: create-signal payload where trigger_source (or any required public text) key is absent or explicitly None. Dynamic payload construction that conditionally sets the key only when a condition holds, leaving it missing on some paths.

Common situations: Optional/required confusion: the field looks optional in older API versions but became mandatory; kwargs-based builders that drop falsy values (payload = {k: v for k, v in data.items() if v}); schema-first clients omitting the field.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/8ef253512d306ae1. Report an issue: GitHub.