Skip to content

FLX-1007

dependency cycle cannot be resolved: orderRouter -> riskCheck -> positionStore

Severity ERROR
Category GRAPH_MODEL
Element CYCLE

The rule

The dependency graph must be acyclic.

Why the compiler says this

Fluxtion dispatches in topological order, computed once at build time. A cycle has no such order — every node in it would have to run before itself — so there is no dispatch sequence to generate.

How to fix it

Break the cycle at whichever reference is not a trigger: mark it @NoTriggerReference (import com.telamin.fluxtion.runtime.annotations.NoTriggerReference) so the node still reads its parent's data without depending on it for ordering, or invert the edge with @PushReference.

Example

Both examples are compiled and put through a real Fluxtion.compile on every build, so the first is guaranteed to produce this diagnostic and the second to build cleanly. Note that the failing example is valid Java — javac is happy, and Fluxtion refuses it for its own reasons.

The code that causes it

package com.telamin.fluxtion.builder.diagnostic.examples;

import com.telamin.fluxtion.builder.generation.config.EventProcessorConfig;
import com.telamin.fluxtion.runtime.annotations.OnEventHandler;
import com.telamin.fluxtion.runtime.annotations.OnTrigger;

/** FLX-1007 — two nodes that each depend on the other. */
public class Flx1007Failing {

    public static class RiskCheck {
        // RiskCheck reads OrderRouter…
        public OrderRouter router;

        @OnEventHandler
        public boolean onOrder(String order) {
            return true;
        }
    }

    public static class OrderRouter {
        // …and OrderRouter reads RiskCheck. There is no order that satisfies both.
        private final RiskCheck risk;

        public OrderRouter(RiskCheck risk) {
            this.risk = risk;
        }

        @OnTrigger
        public boolean onRisk() {
            return true;
        }
    }

    public static void graph(EventProcessorConfig config) {
        RiskCheck risk = new RiskCheck();
        OrderRouter router = new OrderRouter(risk);
        risk.router = router;
        config.addNode(risk, "riskCheck");
        config.addNode(router, "orderRouter");
    }
}

The code that fixes it

package com.telamin.fluxtion.builder.diagnostic.examples;

import com.telamin.fluxtion.builder.generation.config.EventProcessorConfig;
import com.telamin.fluxtion.runtime.annotations.OnEventHandler;
import com.telamin.fluxtion.runtime.annotations.OnTrigger;

/** FLX-1007 fixed — the dependency runs one way. */
public class Flx1007Fixed {

    public static class RiskCheck {
        // The back-reference is gone: risk is upstream, and does not read what it feeds.
        @OnEventHandler
        public boolean onOrder(String order) {
            return true;
        }
    }

    public static class OrderRouter {
        private final RiskCheck risk;

        public OrderRouter(RiskCheck risk) {
            this.risk = risk;
        }

        @OnTrigger
        public boolean onRisk() {
            return true;
        }
    }

    public static void graph(EventProcessorConfig config) {
        RiskCheck risk = new RiskCheck();
        config.addNode(risk, "riskCheck");
        config.addNode(new OrderRouter(risk), "orderRouter");
    }
}

Which builds raise it

Every build path — interpreted, in-process and AOT alike.

Reading it programmatically

This diagnostic is also written to the machine-readable report — the opt-in sidecar (-Dfluxtion.diagnostics.sidecar=true), or FluxtionDiagnostics.capture(...) for a caller that wants the objects:

{
  "code": "FLX-1007",
  "severity": "ERROR",
  "category": "GRAPH_MODEL",
  "element": { "kind": "CYCLE",  }
}

Select findings by severity, never by position: a failing build's report also contains any warnings it found, and diagnostics[0] is not the cause of the failure.


This page is generated from the compiler itself, so the wording above is exactly what a build emits. Do not edit it by hand — it is overwritten whenever the diagnostics are regenerated.