Skip to content

fix(workflow-engine): Prevent ValueError for missing ActionTarget in serializer#119119

Open
sentry[bot] wants to merge 3 commits into
masterfrom
seer/fix/workflow-action-target-none
Open

fix(workflow-engine): Prevent ValueError for missing ActionTarget in serializer#119119
sentry[bot] wants to merge 3 commits into
masterfrom
seer/fix/workflow-action-target-none

Conversation

@sentry

@sentry sentry Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

This PR addresses issue SENTRY-5QVV, where the WorkflowEngineActionSerializer would raise a ValueError: None is not a valid ActionTarget.

Problem:
The WorkflowEngineActionSerializer in src/sentry/incidents/endpoints/serializers/workflow_engine_action.py was attempting to instantiate the ActionTarget enum with None when an Action object's config dictionary was missing the target_type key. This scenario could occur for older Action records or specific action types (e.g., Sentry App actions) where target_type was not present in the config, leading to a ValueError during serialization, particularly when accessing endpoints like /api/0/organizations/{organization_id_or_slug}/combined-rules/.

Solution:

  1. Null Guard: Modified the serialize method in WorkflowEngineActionSerializer to explicitly check if target_type is None before attempting to convert it to an ActionTarget enum member. If target_type is None, the serialized targetType field will now be None.
  2. Type Annotation: Updated the type annotation for target_type from int to int | None to accurately reflect its potential nullability.
  3. Logging: Added a logger.warning call when target_type is None to provide visibility into these cases in production logs without causing a serialization failure.
  4. Regression Test: Added a new test case test_missing_target_type_does_not_raise to tests/sentry/incidents/serializers/test_workflow_engine_action.py to ensure that Action objects with a missing target_type in their config are serialized correctly without raising an error.

Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.

Fixes SENTRY-5QVV

Comment @sentry <feedback> on this PR to have Autofix iterate on the changes.

@sentry sentry Bot requested a review from a team as a code owner July 7, 2026 15:30
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Jul 7, 2026
@alexsohn1126

Copy link
Copy Markdown
Member

hmmmmmm i kinda want tests here........ @sentry can u write some regression tests 👀

@sentry sentry Bot changed the title fix(serializers): Handle None for ActionTarget in workflow engine serialization fix(workflow-engine): Handle missing ActionTarget in action serializer Jul 7, 2026
Comment on lines +79 to 83
if target_type is not None
else None,
"targetIdentifier": get_identifier_from_action(
type_value, str(target_identifier), target_display
),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: If target_identifier is None in the config, casting it to an int will cause a TypeError or ValueError, crashing the serializer.
Severity: HIGH

Suggested Fix

Add a check to ensure target_identifier is not None before attempting to cast it to an integer. Provide a default value or handle the None case gracefully. For example, retrieve the value with target_identifier = obj.config.get("target_identifier") and then add a conditional check if target_identifier is not None: before calling int().

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: src/sentry/incidents/endpoints/serializers/workflow_engine_action.py#L79-L83

Potential issue: If an action's configuration in the database is missing the
`target_identifier` field, the serializer will fail. For actions of type `SENTRY_APP`,
an attempt to call `int(obj.config.get("target_identifier"))` will receive `None`,
raising a `TypeError`. For `PAGERDUTY` or `SENTRY_APP` actions, the code calls
`get_identifier_from_action` with `str(target_identifier)`. If `target_identifier` is
`None`, this becomes `int("None")`, which raises a `ValueError`. This scenario is
plausible in production, as evidenced by the similar bug for `target_type` that this
pull request aims to fix.

Did we get this right? 👍 / 👎 to inform future reviews.

@sentry sentry Bot changed the title fix(workflow-engine): Handle missing ActionTarget in action serializer fix(workflow-engine): Prevent ValueError for missing ActionTarget in serializer Jul 7, 2026
Comment on lines 84 to 86
),
"alertRuleTriggerId": str(alert_rule_trigger_id),
"type": obj.type,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The serializer can crash with a ValueError when a PagerDuty or Sentry App action is missing a target_identifier, as it attempts to run int("None").
Severity: HIGH

Suggested Fix

Before calling get_identifier_from_action, check if target_identifier is None. If it is, handle it gracefully, perhaps by returning None or a default value, to prevent the str() and subsequent int() conversion from crashing when the action type is PagerDuty or Sentry App.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: src/sentry/incidents/endpoints/serializers/workflow_engine_action.py#L84-L86

Potential issue: When serializing a PagerDuty or Sentry App action that is missing a
`target_identifier` in its configuration, the value defaults to `None`. This `None`
value is then cast to the string "None" and passed to the `get_identifier_from_action`
function. For PagerDuty or Sentry App action types, this function attempts to cast the
string "None" to an integer, which raises a `ValueError`. This scenario is likely for
older actions created before the field was required, and the incomplete fix in the pull
request fails to guard against it.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Backend Test Failures

Failures on 990d765 in this run:

tests/sentry/incidents/serializers/test_workflow_engine_action.py::TestActionSerializer::test_missing_target_type_does_not_raiselog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/incidents/serializers/test_workflow_engine_action.py:200: in test_missing_target_type_does_not_raise
    self.critical_action.save()
src/sentry/silo/base.py:157: in override
    return original_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/django/db/models/base.py:902: in save
    self.save_base(
src/sentry/silo/base.py:157: in override
    return original_method(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/django/db/models/base.py:988: in save_base
    pre_save.send(
src/sentry/testutils/pytest/stale_database_reads.py:101: in send
    return old_send(self, sender, **named)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.venv/lib/python3.13/site-packages/django/dispatch/dispatcher.py:189: in send
    response = receiver(signal=self, sender=sender, **named)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/sentry/workflow_engine/receivers/action.py:18: in enforce_action_config_schema
    instance.validate_config(config_schema)
src/sentry/workflow_engine/models/json_config.py:17: in validate_config
    raise ValidationError(f"Invalid config: {e.message}")
E   jsonschema.exceptions.ValidationError: Invalid config: 'target_type' is a required property

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant