Repository navigation
lore deploy silently skips an unloadable manifest and exits 0 #368
Description
lore deploy silently skips a manifest it cannot load, and in the common case exits 0 while having deployed less than the user asked for.
Mechanism
parseLoreDeployConfig loads each @manifest argument at cmd/lore/lore/commands.go:108. When manifest.Load fails it prints to the console and continues:
m, err := manifest.Load(arg[1:])
if err != nil {
cli.Error("Error reading manifest %q: %v", arg[1:], err)
continue
}The error is swallowed at the point it occurs, which is why the function returns nil unconditionally at cmd/lore/lore/commands.go:126 — and why its signature carries //nolint:unparam // error return reserved for future use at cmd/lore/lore/commands.go:89. That comment documents a consequence as though it were an intention. The error return is not reserved for future use; it is dead because a live failure path was downgraded to a log line.
manifest.Load is document.ReadFile[PackagesManifest] (internal/manifest/manifest.go:81), so it fails on a missing file, an unreadable file, a malformed document, or a schema mismatch — all ordinary user errors, including a simple typo in a filename.
Observable failures
1. Silent partial deploy, exit 0.
lore deploy @typo.yaml some-package
typo.yaml is skipped, some-package deploys, len(resolved) != 0, and runDeploy returns nil. The user asked for two things, received one, and the exit code reports success. A CI step wrapping this goes green on a half-completed deploy.
2. Misdiagnosed failure.
lore deploy @typo.yaml
cfg.Packages stays empty and runDeploy returns "no packages to deploy" from cmd/lore/lore/commands.go:81. That is the wrong cause — the manifest failed to load, and that message has already scrolled past. The exit code is correct here; the diagnosis is not.
Scope
Parsing happens before any deployment executes, so aborting on a bad manifest costs the user nothing that has already been done. This is cheap to fix correctly.
Found during the issue #365 audit while reviewing cmd/lore/lore/commands.go for phase 1b. Not folded into that phase: 1b is behavior-preserving decomposition under the #312 discipline, and a semantic fix hidden inside an extract-method diff is exactly what that discipline forbids.
Activity
docs: two bugs found during the phase 1b review, and the measured 1b …
refactor(lore): decompose runOnboard and generateManifest (#371)
David-Noble-at-work commentedon Aug 12, 2026
Same pattern elsewhere, found during phase 1b-ii:
buildIndex(cmd/devlore-index/main.go:195) carries//nolint:unparam // error return reserved for future use— and its error return is dead for the same reason this issue documents:listFilesfailures are swallowed with acontinueinside the loop. A missing asset-type directory is arguably a legitimate skip, so the severity is lower than the deploy case, but the suppression's stated reason is the same fiction. Whatever ruling settles this issue should be applied there too.refactor(internal): decompose promptForProvider and devlore-index main (