jenkinsci/jenkins · error · AbstractMethodError

Plugin class '{getClass().getName()}' does not override eith

Error message

Plugin class '{getClass().getName()}' does not override either overload of the decorateLogger method.

What it means

AbstractMethodError thrown by the deprecated ConsoleLogFilter.decorateLogger(AbstractBuild, OutputStream) when a subclass overrides neither that method nor decorateLogger(Run, OutputStream). Util.isOverridden detects the missing Run-based override, so the old method cannot forward and aborts. The class is documented as requiring the Run overload to be implemented.

Source

Thrown at core/src/main/java/hudson/console/ConsoleLogFilter.java:72

 */
public abstract class ConsoleLogFilter implements ExtensionPoint {
    /**
     * Called on the start of each build, giving extensions a chance to intercept
     * the data that is written to the log.
     *
     * @throws AbstractMethodError
     *     when a plugin overrides neither this method nor {@link #decorateLogger(Run, OutputStream)}.
     *
     * @deprecated as of 1.632. Use {@link #decorateLogger(Run, OutputStream)}
     */
    @Deprecated
    public OutputStream decorateLogger(AbstractBuild build, OutputStream logger) throws IOException, InterruptedException {
        if (Util.isOverridden(ConsoleLogFilter.class, getClass(), "decorateLogger", Run.class, OutputStream.class)) {
            // old client calling newer implementation. forward the call.
            return decorateLogger((Run) build, logger);
        } else {
            // happens only if the subtype fails to override either decorateLogger method
            throw new AbstractMethodError("Plugin class '" + this.getClass().getName() + "' does not override " +
                    "either overload of the decorateLogger method.");
        }
    }

    /**
     * Called on the start of each build, giving extensions a chance to intercept
     * the data that is written to the log.
     *
     * <p>
     * Even though this method is not marked 'abstract', this is the method that must be overridden
     * by extensions.
     */
    public OutputStream decorateLogger(Run build, OutputStream logger) throws IOException, InterruptedException {
        // this implementation is backward compatibility thunk in case subtypes only override the
        // old signature (AbstractBuild,OutputStream)

        if (build instanceof AbstractBuild) {
            // maybe the plugin implements the old signature.

View on GitHub (pinned to 2e228ff40b)

Solutions

  1. Override decorateLogger(Run, OutputStream) in the subclass.
  2. If you must support pre-1.632 cores, override both overloads.
  3. Audit ConsoleLogFilter subclasses after a core upgrade.

Example fix

// before
public class MyFilter extends ConsoleLogFilter { }
// after
public class MyFilter extends ConsoleLogFilter {
    @Override
    public OutputStream decorateLogger(Run build, OutputStream logger)
            throws IOException, InterruptedException {
        return new MyStream(logger);
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (!Util.isOverridden(ConsoleLogFilter.class, filter.getClass(),
        "decorateLogger", Run.class, OutputStream.class)) {
    // subclass must override the Run overload
}

Try / catch

try { filter.decorateLogger(build, out); }
catch (AbstractMethodError e) { /* subclass overrides neither overload */ }

Prevention

When it happens

Trigger: A plugin's ConsoleLogFilter extension that overrides neither decorateLogger overload, invoked through the legacy AbstractBuild API (older core or another plugin).

Common situations: Plugin compiled against an old core; an empty/stub ConsoleLogFilter subclass; core upgraded past 1.632 where the Run overload became the expected one.

Related errors


AI-assisted analysis of jenkinsci/jenkins@2e228ff40b (2026-08-14). Data as JSON: /api/errors/e4067692554d6a57. Report an issue: GitHub.