odysseus-dev/odysseus · warning · HTTPException

Trigger count is required for event-triggered tasks

Error message

Trigger count is required for event-triggered tasks

What it means

Create-task validation: trigger_type 'event' additionally requires trigger_count (how many times/how many occurrences the event trigger consumes) to be set — a falsy value (0, null, missing) is rejected with HTTP 400.

Source

Thrown at routes/task_routes.py:477

            raise HTTPException(400, "Action name is required for action tasks")
        # Block shell-executing action types for non-admins. action_run_local
        # uses subprocess.run(shell=True) and ssh_command / run_script run
        # arbitrary commands.
        _require_admin_for_task_action(user, req.task_type, req.action)
        if req.trigger_type == "schedule" and not req.schedule:
            raise HTTPException(400, "Schedule is required for schedule-triggered tasks")
        if req.trigger_type == "schedule" and req.schedule == "cron" and not req.cron_expression:
            raise HTTPException(400, "Cron expression is required for cron schedule")
        if req.trigger_type == "schedule" and req.schedule == "cron" and req.cron_expression:
            try:
                from croniter import croniter
                croniter(req.cron_expression)
            except Exception:
                raise HTTPException(400, "Invalid cron expression")
        if req.trigger_type == "event" and not req.trigger_event:
            raise HTTPException(400, "Event name is required for event-triggered tasks")
        if req.trigger_type == "event" and not req.trigger_count:
            raise HTTPException(400, "Trigger count is required for event-triggered tasks")

        # Auto-generate name
        name = req.name
        if not name:
            if req.task_type == "action":
                from src.builtin_actions import BUILTIN_ACTION_INFO
                name = BUILTIN_ACTION_INFO.get(req.action, req.action or "Action Task")
            elif req.prompt:
                name = await _generate_task_name(req.prompt, owner=user)
            else:
                name = "Untitled Task"

        # Compute next_run for schedule-triggered tasks
        next_run = None
        sched_date = None
        if req.trigger_type == "schedule":
            if req.schedule == "once" and req.scheduled_date:
                try:

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Include a positive integer trigger_count (e.g. 1) whenever trigger_type is 'event'.
  2. Default the count field to 1 in the client form so it is always serialized.
  3. After upgrading the backend, re-check the TaskCreate schema for newly required event fields.

Example fix

// before
{trigger_type: 'event', trigger_event: 'email.received'}

// after
{trigger_type: 'event', trigger_event: 'email.received', trigger_count: 1}
Defensive patterns

Strategy: validation

Validate before calling

function validateEventCount(p) {
  if (p.trigger_type === 'event' && !(Number(p.trigger_count) > 0))
    throw new ValidationError('Trigger count must be a positive integer');
  return {...p, trigger_count: Number(p.trigger_count)};
}

Type guard

function hasTriggerCount(p: unknown): p is {trigger_type: 'event'; trigger_count: number} {
  return typeof p === 'object' && p !== null &&
    typeof (p as any).trigger_count === 'number' && (p as any).trigger_count > 0;
}

Prevention

When it happens

Trigger: POST /api/tasks with {"trigger_type": "event", "trigger_event": "..."} but trigger_count omitted, null, or 0.

Common situations: Client sends trigger_count only for recurring mode; form defaults the count field to 0; schema change from optional to required trigger_count after an upgrade so old payloads now fail.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/2c5b3841864bce55. Report an issue: GitHub.