MGS1012: cross-project output forms a dependency cycle
A target declared a cross-project input on a project and a cross-project output into that same project. The two imply opposite build orders, so there is no order that satisfies both.
[MGS1012] renderer: ctx.writesFiles writes "out.html" into "site", so site must run
after renderer, but renderer already depends on site; a target cannot both read
from and write into the same project
Why
The two cross-project declarations are not symmetric, and that is the whole point of having both:
| Declaration | Meaning | Edge |
|---|---|---|
ctx.readsFiles(site.file("src.md")) |
I read a file site owns |
renderer depends on site |
ctx.writesFiles(site.file("out.html")) |
I produce a file site owns |
site depends on renderer |
An input says build me after them, so I read finished bytes. An output says build them after me, so they see finished bytes. Declare both against one project and each is waiting on the other.
This is not an exotic mistake. It is the most natural thing to reach for: read a project's sources, render them, write the result back next to them. The shape is reasonable; it is the project boundary that is drawn in the wrong place.
Why it fails here and not later
The dependency graph would catch the cycle eventually, but far too late to be useful:
- The error named neither project nor file - just
graph: dependency cycle. - It took down
magus graphand the entire affected pipeline for every project in the workspace, not the two involved. - It was scope-dependent. A run selecting only the writer never builds the full
graph, so
magus run build rendererreported success on a workspace thatmagus graph depsrefused to load at all.
Failing at load makes it deterministic and attributable: the same workspace fails the same way for every command, and the message names both halves.
Resolution
Pick whichever is true of your target.
It is a consumer. If it only reads site and the output was a mistake, drop
the cross-project output and write into its own tree:
ctx.readsFiles(site.file("src.md"));
ctx.writesFiles("dist/out.html");
It is a producer. If it genuinely generates part of site, drop the
cross-project input. A writer does not usually need to declare an input on the
project it writes into - and if it reads a different project's sources, declare
the input there instead.
Both are true. Then the read and the write are two different concerns sharing
one project by accident. Split the generated file into a third project that
neither reads from, and have site declare a cross-project input on it. That is
the shape the ordering model is built for, and it stays acyclic.
See also
- MGS1011 - a cross-project output naming a project magus cannot use
- Cross-project dependencies