{"record":{"id":"30480a372f654efb","repo":"beemdevelopment/Aegis","slug":"bad-counter-d","errorCode":null,"errorMessage":"bad counter: %d","messagePattern":"bad counter: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/main/java/com/beemdevelopment/aegis/otp/HotpInfo.java","lineNumber":70,"sourceCode":"        try {\n            obj.put(\"counter\", getCounter());\n        } catch (JSONException e) {\n            throw new RuntimeException(e);\n        }\n        return obj;\n    }\n\n    public long getCounter() {\n        return _counter;\n    }\n\n    public static boolean isCounterValid(long counter) {\n        return counter >= 0;\n    }\n\n    public void setCounter(long counter) throws OtpInfoException {\n        if (!isCounterValid(counter)) {\n            throw new OtpInfoException(String.format(\"bad counter: %d\", counter));\n        }\n        _counter = counter;\n    }\n\n    public void incrementCounter() throws OtpInfoException {\n        setCounter(getCounter() + 1);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof HotpInfo)) {\n            return false;\n        }\n\n        HotpInfo info = (HotpInfo) o;\n        return super.equals(o) && getCounter() == info.getCounter();\n    }\n}","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/otp/HotpInfo.java#L52-L88","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the counter value passed to setCounter (or the counter parameter in the URI/JSON being imported) is >= 0.","When importing, validate the counter with HotpInfo.isCounterValid(counter) before constructing/assigning.","If incrementCounter overflows, reset or rotate the credential rather than persisting a wrapped negative counter."],"exampleFix":"// before\nhotp.setCounter(counterFromUri); // may be -1\n\n// after\nif (HotpInfo.isCounterValid(counterFromUri)) {\n    hotp.setCounter(counterFromUri);\n} else {\n    throw new IllegalArgumentException(\"invalid counter in URI: \" + counterFromUri);\n}","handlingStrategy":"validation","validationCode":"if (!HotpInfo.isCounterValid(counter)) {\n    throw new IllegalArgumentException(\"counter must be >= 0: \" + counter);\n}","typeGuard":null,"tryCatchPattern":"try {\n    hotp.setCounter(counter);\n} catch (OtpInfoException e) {\n    // invalid (negative/overflowed) counter; reset to 0 or reject the entry\n    throw new ImportException(\"invalid HOTP counter\", e);\n}","preventionTips":["Validate the counter field of every otpauth://hotp URI/backup entry at import time.","Clamp or reject negative counters before persistence.","Watch for incrementCounter overflow on long-lived credentials."],"tags":["otp","hotp","counter","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6f4e5925a97e4e91593f1542085eae03432a759","analyzedAt":"2026-09-08T00:46:31.111Z","contentChangedAt":"2026-09-08T00:46:31.111Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}