Skip to content

asset refresh: "Compilation errors exist from a previous build" doesn't show the actual errors #47

Description

@Niaobu

Problem

When unityctl asset refresh finds nothing new to compile but the project is already in a failed-compile state, the CLI prints only:

Error: Compilation errors exist from a previous build

and exits 1, without listing the errors. This happens via the hasCompilationErrors && !compilationTriggered branch in UnityCtl.Cli/AssetCommands.cs, which is driven by EditorUtility.scriptCompilationFailed on the Unity side — a bare bool, so no diagnostics travel with the response.

Compare with the compilationTriggered path, which prints the full file(line,col): error CSxxxx: ... list. From the caller's perspective the project is equally broken in both cases, but in one of them there is no way to find out why.

Why it matters

This is a dead end for agents (and humans) alike:

  • Re-running asset refresh returns the same one-liner — the refresh is a no-op since nothing changed, so compilation is never re-triggered and the errors are never re-emitted.
  • The natural next step, script eval to query the compile state, fails too: eval compilation itself can be affected, and there's no supported API agents reliably guess (InternalEditorUtility.GetAllScriptCompilationErrors etc. don't exist).
  • The actual workarounds are non-obvious: touch a script to force a recompile, or scrape logs --level error / Editor.log.

The state is easy to get into: errors introduced while the bridge wasn't connected yet, a failed compile from a previous session (failed compiles persist across editor restarts), or a compile kicked off by the editor itself rather than by a unityctl command.

Proposed fix

The plugin already receives full CompilerMessage lists via CompilationPipeline.assemblyCompilationFinished (UnityCtlBootstrap) and forwards them on the CompilationFinished event. Suggestion:

  1. Cache the last failed compile's messages plugin-side (a failed compile blocks the domain reload, so an in-memory cache survives; SessionState could cover editor restarts).
  2. Include the cached messages in the asset.refresh response when hasCompilationErrors && !compilationTriggered, and have the CLI print them through the existing DisplayCompilationErrors path.
  3. If no cached messages are available (errors predate plugin load), fall back to forcing a recompile via CompilationPipeline.RequestScriptCompilation() so the messages get regenerated — or at minimum extend the error text with a recovery hint, e.g.:
Error: Compilation errors exist from a previous build
  (run 'unityctl logs --level error' to see them, or modify a script and re-run 'unityctl asset refresh' to recompile)

Even just (3) would turn a dead end into a recoverable state; (1)+(2) make it seamless.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions