Quick answer: GUI.color, GUI.contentColor, and GUI.backgroundColor are global statics. Helper methods that set them must restore the previous value, ideally with a try/finally block or a custom IDisposable scope used via using. Otherwise an exception or early return leaks the color.

Here is how to fix Unity IMGUI custom editors where a single colored section bleeds into every following control. You set GUI.color = Color.red for a warning label, draw it, and forget to restore the previous value — or worse, an exception fires inside the colored block. The rest of your inspector renders red. The fix is a tiny scope helper that you should copy into every editor utility you write.

The Symptom

An EditorWindow or custom Inspector renders mostly correctly. One section appears tinted (red, green, semi-transparent) when it should not be. The tint persists across other inspector sections rendered after it. Closing and reopening the inspector fixes it — until the offending control runs again.

What Causes This

GUI.color is global state. Unlike modern UI frameworks that pass color as a parameter to each draw call, IMGUI stores tint as a global. Set it once and every subsequent control inherits it.

Manual restore forgotten. Many helper methods set color, draw, and forget to restore. The static value is whatever the last set was.

Exceptions skip the restore. Even if you do set color back at the end of a method, an exception thrown mid-method skips that line. The static value sticks.

Early returns. An if (!something) return; after a color set bypasses the restore line.

The Fix

Step 1: Define a ColorScope helper.

using System;
using UnityEngine;

public readonly struct GuiColorScope : IDisposable
{
    private readonly Color previous;

    public GuiColorScope(Color color)
    {
        previous = GUI.color;
        GUI.color = color;
    }

    public void Dispose() { GUI.color = previous; }
}

// Mirror struct for backgroundColor / contentColor as needed
public readonly struct GuiBackgroundScope : IDisposable
{
    private readonly Color previous;
    public GuiBackgroundScope(Color color)
    {
        previous = GUI.backgroundColor;
        GUI.backgroundColor = color;
    }
    public void Dispose() { GUI.backgroundColor = previous; }
}

Step 2: Use it with using-syntax.

void DrawWarning(string text)
{
    using (new GuiColorScope(new Color(1f, 0.6f, 0.2f)))
    {
        GUILayout.Label(text, EditorStyles.boldLabel);
    }
    // GUI.color is automatically restored here, even on exception
}

Step 3: Apply to nested sections. Scopes nest correctly. Each level captures the value from the previous level, restores it on dispose:

using (new GuiColorScope(Color.red))
{
    GUILayout.Label("Outer red");

    using (new GuiColorScope(Color.green))
        GUILayout.Label("Inner green");

    GUILayout.Label("Back to red");
}
GUILayout.Label("Default again");

Step 4: Use built-in scopes where they exist.

// EditorGUI.IndentLevelScope - built in
using (new EditorGUI.IndentLevelScope())
    EditorGUILayout.PropertyField(prop);

// EditorGUI.DisabledScope - built in
using (new EditorGUI.DisabledScope(!enabled))
    EditorGUILayout.FloatField("Speed", speed);

// GUILayout.HorizontalScope / VerticalScope - built in
using (new GUILayout.HorizontalScope())
{
    GUILayout.Button("A");
    GUILayout.Button("B");
}

Step 5: Use try/finally as a fallback. If you cannot drop in a scope helper for some reason, at least bracket the change:

Color prev = GUI.color;
GUI.color = Color.red;
try
{
    DrawSomething();
}
finally
{
    GUI.color = prev;
}

Why Editor Code Matters Here

Color leakage in custom editors is mostly cosmetic, but in CustomPropertyDrawers it leaks into the entire inspector for every selected object. A single bad drawer can tint your entire project view. Editor tools written with scopes from day one stay clean as the codebase grows.

“IMGUI is a stateful machine. The using statement is the cleanest way to admit that and contain the damage.”

Related Issues

For other custom editor issues, see SerializedField Not Showing Inspector and Prefab Changes Not Saving.

Scopes are cheap. Leaks are loud. Wrap every color change.