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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions