beemdevelopment/Aegis · error

bad counter

Error message

bad counter: %d

What it means

HotpInfo.setCounter validates that an HOTP counter is non-negative via isCounterValid before storing it. A negative counter cannot occur in valid HOTP operation, so OtpInfoException('bad counter: %d') is thrown to reject the invalid value.

Solutions

  1. Ensure the counter value passed to setCounter (or the counter parameter in the URI/JSON being imported) is >= 0.
  2. When importing, validate the counter with HotpInfo.isCounterValid(counter) before constructing/assigning.
  3. If incrementCounter overflows, reset or rotate the credential rather than persisting a wrapped negative counter.

Example fix

// before
hotp.setCounter(counterFromUri); // may be -1

// after
if (HotpInfo.isCounterValid(counterFromUri)) {
    hotp.setCounter(counterFromUri);
} else {
    throw new IllegalArgumentException("invalid counter in URI: " + counterFromUri);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!HotpInfo.isCounterValid(counter)) {
    throw new IllegalArgumentException("counter must be >= 0: " + counter);
}

Try / catch

try {
    hotp.setCounter(counter);
} catch (OtpInfoException e) {
    // invalid (negative/overflowed) counter; reset to 0 or reject the entry
    throw new ImportException("invalid HOTP counter", e);
}

Prevention

When it happens

Trigger: Calling setCounter(negativeValue); calling incrementCounter() when the counter is Long.MIN_VALUE or would overflow to negative (counter + 1 < 0); parseUri encountering an otpauth://hotp URI with a negative counter parameter.

Common situations: Importing a malformed otpauth URI or encrypted-backup JSON with a negative counter; integer overflow after an astronomically large number of HOTP increments; hand-editing entry data.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08). Data as JSON: /api/errors/30480a372f654efb. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/com/beemdevelopment/aegis/otp/HotpInfo.java:70

        try {
            obj.put("counter", getCounter());
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return obj;
    }

    public long getCounter() {
        return _counter;
    }

    public static boolean isCounterValid(long counter) {
        return counter >= 0;
    }

    public void setCounter(long counter) throws OtpInfoException {
        if (!isCounterValid(counter)) {
            throw new OtpInfoException(String.format("bad counter: %d", counter));
        }
        _counter = counter;
    }

    public void incrementCounter() throws OtpInfoException {
        setCounter(getCounter() + 1);
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof HotpInfo)) {
            return false;
        }

        HotpInfo info = (HotpInfo) o;
        return super.equals(o) && getCounter() == info.getCounter();
    }
}

View on GitHub (pinned to d6f4e5925a)