influxdata/influxdb · error · PluginError

shouldn't have table trigger for scheduled plugin

Error message

shouldn't have table trigger for scheduled plugin

What it means

Raised by ScheduleRunner::try_new when a scheduled plugin is constructed with a table-based trigger specification (AllTablesWalWrite or SingleTableWalWrite). Scheduled plugins run on cron schedules, not on WAL write events, so the library rejects the combination.

Solutions

  1. Use TriggerSpecificationDefinition::Schedule with a valid cron string for this plugin.
  2. In SQL, use the SCHEDULE clause instead of table triggers: CREATE TRIGGER ... AT ... SCHEDULE '...'.
  3. Alternatively use a WAL-trigger-compatible plugin if per-write execution is desired.

Example fix

// before
CREATE TRIGGER "t" ON TABLE cpu AFTER INSERT ...  // for a scheduled plugin
// after
CREATE TRIGGER "t" ... SCHEDULE '*/5 * * * *'
Defensive patterns

Strategy: validation

Validate before calling

fn valid_spec_for_scheduled_plugin(spec: &TriggerSpecificationDefinition) -> bool {
    matches!(spec, TriggerSpecificationDefinition::Schedule { .. })
}

Prevention

When it happens

Trigger: Calling try_new (plugin trigger setup) with a plugin defined as scheduled and a trigger spec of table/WAL-write kind.

Common situations: Admin writes CREATE TRIGGER ... ON TABLE x (or ALL TABLES) for a plugin that only supports SCHEDULE; UI/CLI mixing trigger types.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19). Data as JSON: /api/errors/9fd4469facd18c62. Report an issue: GitHub.

Appendix: source

Thrown at influxdb3_processing_engine/src/plugins.rs:172

enum Schedule {
    Cron(Box<OwnedScheduleIterator<Utc>>),
    Every(Duration),
}

struct ScheduleTriggerRunner {
    schedule: Schedule,
    next_trigger_time: Option<DateTime<Utc>>,
}

impl ScheduleTriggerRunner {
    fn try_new(
        trigger_spec: &TriggerSpecificationDefinition,
        time_provider: Arc<dyn TimeProvider>,
    ) -> Result<Self, PluginError> {
        match trigger_spec {
            TriggerSpecificationDefinition::AllTablesWalWrite
            | TriggerSpecificationDefinition::SingleTableWalWrite { .. } => {
                Err(anyhow!("shouldn't have table trigger for scheduled plugin").into())
            }
            TriggerSpecificationDefinition::RequestPath { .. } => {
                Err(anyhow!("shouldn't have request path trigger for scheduled plugin").into())
            }
            TriggerSpecificationDefinition::Schedule { schedule } => {
                let schedule = CronSchedule::from_str(schedule.as_str())
                    .context("cron schedule should be parsable")?;
                Ok(Self::new_cron(schedule, time_provider))
            }
            TriggerSpecificationDefinition::Every { duration } => {
                // check that duration isn't longer than a year, so we avoid overflows.
                if *duration > parse_duration("1 year").unwrap() {
                    return Err(anyhow!("schedule duration cannot be greater than 1 year").into());
                }
                Ok(Self::new_every(
                    Duration::from_std(*duration)
                        .context("should be able to convert durations. ")?,
                    time_provider,

View on GitHub (pinned to 06200ef96b)