microg/GmsCore · error · IllegalArgumentException
rotationTimeHours is not in range of 0x1-0xffff
Error message
rotationTimeHours is not in range of 0x1-0xffff
What it means
ThreadNetworkCredentials.SecurityPolicy's constructor validates that rotationTimeHours is within the Thread-spec range 0x1-0xffff and throws IllegalArgumentException otherwise. The rotation time is a 16-bit unsigned field in the Thread network dataset, so 0 or values above 65535 are unrepresentable and invalid.
Source
Thrown at play-services-threadnetwork/src/main/java/com/google/android/gms/threadnetwork/ThreadNetworkCredentials.java:177
}
/**
* The class represents Thread Security Policy.
*/
public static class SecurityPolicy {
private final int rotationTimeHours;
private final byte[] flags;
/**
* Creates a new {@link SecurityPolicy} object.
*
* @param rotationTimeHours the value for Thread key rotation in hours. Must be in range of 0x1-0xffff.
* @param flags security policy flags with length of either 1 byte for Thread 1.1 or 2 bytes for Thread 1.2 or higher.
* @throws IllegalArgumentException if {@code rotationTimeHours} is not in range of 0x1-0xffff or
* length of flags is smaller than {@link ThreadNetworkCredentials#LENGTH_MIN_SECURITY_POLICY_FLAGS}.
*/
public SecurityPolicy(int rotationTimeHours, byte[] flags) {
if (rotationTimeHours < 1 || rotationTimeHours > 0xffff) throw new IllegalArgumentException("rotationTimeHours is not in range of 0x1-0xffff");
if (flags.length < LENGTH_MIN_SECURITY_POLICY_FLAGS) throw new IllegalArgumentException("length of flags is smaller than LENGTH_MIN_SECURITY_POLICY_FLAGS");
this.rotationTimeHours = rotationTimeHours;
this.flags = flags;
}
/**
* Returns 1 byte flags for Thread 1.1 or 2 bytes flags for Thread 1.2.
*/
public byte[] getFlags() {
return flags;
}
/**
* Returns the Security Policy Rotation Time in hours.
*/
public int getRotationTimeHours() {
return rotationTimeHours;
}View on GitHub (pinned to 157c9d86ac)
Solutions
- Use a value in [1, 65535]; the Thread default rotation time is 672 hours
- Validate the parsed value before constructing SecurityPolicy
- Replace 0 placeholder defaults with the spec default (672)
- If the source is unsigned 16-bit data, mask with & 0xFFFF and confirm it's nonzero
Example fix
// before SecurityPolicy policy = new SecurityPolicy(0, flags); // IllegalArgumentException // after int rotationTimeHours = 672; // Thread default, must be 1..0xffff SecurityPolicy policy = new SecurityPolicy(rotationTimeHours, flags);
Defensive patterns
Strategy: validation
Validate before calling
if (rotationTimeHours < 1 || rotationTimeHours > 0xffff) throw new IllegalArgumentException("rotationTimeHours must be in 0x1-0xffff, got " + rotationTimeHours); Type guard
boolean isValidRotationTime(int hours) { return hours >= 1 && hours <= 0xffff; } Try / catch
try {
SecurityPolicy p = new SecurityPolicy(rotationTimeHours, flags);
} catch (IllegalArgumentException e) {
// fall back to the Thread default of 672 hours
} Prevention
- Use the Thread default (672 hours) instead of 0 placeholders
- Mask unsigned 16-bit fields with & 0xFFFF and check nonzero
- Validate dataset fields parsed from TLV/JSON before constructing objects
When it happens
Trigger: Constructing a SecurityPolicy with rotationTimeHours == 0 or > 65535, e.g. from a dataset field parsed without range validation or a default of 0 used to mean 'unset'.
Common situations: Initializing rotationTimeHours to 0 as a placeholder; reading the value from a TLV parser that returns a wider int; config files with 0 meaning 'use default'.
Related errors
- page exceeds range [0, 255].
- the id is not of length 16 bytes
- length of flags is smaller than LENGTH_MIN_SECURITY_POLICY_F
- deleteAll was set to true but keys were also provided
- Element in keys cannot be null or empty
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/87ea0894b94188b9.
Report an issue: GitHub.