Skip to content

lore deploy silently skips an unloadable manifest and exits 0 #368

Open

Description

@David-Noble-at-work

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.


Epic: #446 · Feature: #462

Activity

  1. David-Noble-at-work commented on Aug 12, 2026

    @David-Noble-at-work
    ContributorAuthor

    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: listFiles failures are swallowed with a continue inside 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.

  2. added
    taskImplementation work item
    bugSomething isn't working
    Severity:HighA supported path is broken with no workaround
    and removed
    taskImplementation work item
    on Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Epic:LorePackaginglore packaging and the registryPriority:P1This cycleSeverity:HighA supported path is broken with no workaroundbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions