alibaba/canal · error · IllegalArgumentException

Unexcepted limit: {}

Error message

Unexcepted limit: {}

What it means

Thrown by FileLogFetcher.fetch() in the else branch when 'limit' takes an unexpected value that violates the method's internal buffer-state invariant (the code comments it 'Should not happen'). It is a defensive guard indicating the fetcher's buffer positions got into an inconsistent state, almost always a consequence of upstream corruption rather than normal operation.

Source

Thrown at dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/FileLogFetcher.java:158

                    return true;
                } else {
                    ensureCapacity((int) eventLen);
                }
            }

            System.arraycopy(buffer, origin, buffer, 0, limit);
            position -= origin;
            origin = 0;
            final int len = fin.read(buffer, limit, buffer.length - limit);
            if (len >= 0) {
                limit += len;

                /* More binlog to fetch */
                return true;
            }
        } else {
            /* Should not happen. */
            throw new IllegalArgumentException("Unexcepted limit: " + limit);
        }

        /* Reach binlog file end */
        return false;
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.taobao.tddl.dbsync.binlog.LogFetcher#close()
     */
    public void close() throws IOException {
        if (fin != null) {
            fin.close();
        }

        fin = null;
    }

View on GitHub (pinned to 87be50e876)

Solutions

  1. Treat this as data corruption: re-verify the binlog file with mysqlbinlog on the source; if it fails there too, the file is damaged.
  2. Ensure a single FileLogFetcher instance is not shared across threads (it is not thread-safe).
  3. Restart the fetch from an earlier known-good position/file rather than continuing past the corrupt region.
  4. If reproducible on a known-good file, check for a subclass overriding LogBuffer/LogFetcher methods that mismanage position/limit.
Defensive patterns

Strategy: try-catch

Validate before calling

// Guard the fetcher's buffer invariant defensively in a wrapper
public boolean safeFetch(FileLogFetcher f) throws IOException {
    try { return f.fetch(); }
    catch (IllegalArgumentException e) {
        if (e.getMessage().startsWith("Unexcepted limit"))
            throw new IOException("binlog corruption / unsafe concurrent use", e);
        throw e;
    }
}

Try / catch

try { while (fetcher.fetch()) { /* decode */ } }
catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Unexcepted limit"))
        throw new IOException("file/log fetcher state corrupted - re-open from good position", e);
    throw e;
}

Prevention

When it happens

Trigger: fetch() computes buffer state and reaches the else branch whose precondition on 'limit' is not met - i.e. limit is negative or larger than buffer capacity after the compact/read logic, which should be impossible given the preceding arithmetic.

Common situations: A corrupted/truncated binlog file feeding the reader inconsistent event lengths; a race where the same FileLogFetcher is used concurrently (not thread-safe); memory corruption or a bug in a downstream subclass overriding ensureCapacity/forward that breaks position accounting.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/403e4cb178c81eae. Report an issue: GitHub.