immich-app/immich · error · Error

Unable to infer workflow event type from steps

Error message

Unable to infer workflow event type from steps

What it means

execute cannot determine which WorkflowType a workflow's steps correspond to: after iterating the steps and matching them against known target types, no type could be inferred. This is an internal invariant violation indicating misconfigured workflow data — steps that map to no known event type.

Solutions

  1. Inspect the workflow's steps in the database/definition and verify each step's method maps to a known workflow type.
  2. Delete or re-create the broken workflow via the workflow editor so steps are re-validated against current methods.
  3. Update Immich (or the workflow definitions) if a version migration renamed step methods; run any pending migrations.
  4. If programmatically creating workflows, always run them through resolveAndValidateSteps before persisting so bad steps are rejected early.

Example fix

// before
const steps = workflow.steps; // possibly stale/unvalidated
await execute(workflowId, steps);
// after
const steps = await resolveAndValidateSteps(workflow.trigger, workflow.steps);
if (steps.length === 0) return; // skip empty/invalid workflows
await execute(workflowId, steps);
Defensive patterns

Strategy: validation

Validate before calling

const inferType = (steps: Step[]) =>
  steps.map((s) => TARGET_TYPES.find((t) => matches(s, t))).find(Boolean);
if (!steps.length || !inferType(steps)) {
  logger.warn('skipping workflow with uninferrable steps');
  return;
}

Type guard

const hasKnownType = (steps: Step[]): steps is Step[] & { length: number } =>
  steps.length > 0 && steps.every((s) => KNOWN_TYPES.includes(s.type as T));

Try / catch

try {
  await execute(workflowId, steps);
} catch (e) {
  if (e.message === 'Unable to infer workflow event type from steps') {
    logger.error(`workflow ${workflowId} has unrecognizable steps; skipping`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: handleAssetTrigger invokes execute for a workflow whose stored steps array is empty or whose steps' methods resolve to no recognized WorkflowType, so the `type` variable remains undefined after the matching loop.

Common situations: Workflow definitions saved by an older version whose step methods were renamed/removed; hand-edited or imported workflow JSON with unknown step payloads; a workflow created with zero steps; plugin methods removed from the registry while workflows still reference them.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/54f9148419b123ab. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/workflow-execution.service.ts:408

    getHandler: (type: T) => ExecuteOptions<T> | undefined,
  ) {
    const workflow = await this.workflowRepository.getForWorkflowRun(workflowId);
    if (!workflow) {
      return;
    }

    // TODO infer from steps
    let type: T | undefined;
    for (const targetType of Object.values(WorkflowType)) {
      const isMissing = workflow.steps.some((step) => !step.types.includes(targetType));
      if (!isMissing) {
        type = targetType as unknown as T;
        break;
      }
    }

    if (!type) {
      throw new Error('Unable to infer workflow event type from steps');
    }

    const handler = getHandler(type);
    if (!handler) {
      this.logger.error(`Misconfigured workflow ${workflowId}: no handler for type ${type}`);
      return;
    }

    const { read, write } = handler;
    const readResult = await read(type);
    let data = readResult.data;
    const runId = crypto.randomUUID();

    for (const step of workflow.steps) {
      try {
        const payload: WorkflowEventPayload<typeof type> = {
          trigger: workflow.trigger,
          type,

View on GitHub (pinned to e55ac299a4)