halo-dev/halo · warning · InvalidCookieException

Cookie token[1] did not contain a valid number (contained '{

Error message

Cookie token[1] did not contain a valid number (contained '{}')

What it means

After Base64-decoding the remember-me cookie and splitting on the delimiter, getTokenExpiryTime() parses token slot [1] as a long (epoch millis). If Long.parseLong throws NumberFormatException, the slot is not a valid expiry timestamp and an InvalidCookieException is thrown. The expiry is the second token in the cookie payload (index 1).

Source

Thrown at application/src/main/java/run/halo/app/security/authentication/rememberme/TokenBasedRememberMeServices.java:196

                                    throw new InvalidCookieException(
                                            "Cookie contained signature '" + actualTokenSignature
                                                    + "' but expected '"
                                                    + expectedTokenSignature + "'");
                                }
                            })
                            .thenReturn(userDetails);
                });
    }

    protected boolean isTokenExpired(long tokenExpiryTime) {
        return tokenExpiryTime < System.currentTimeMillis();
    }

    private long getTokenExpiryTime(String[] cookieTokens) {
        try {
            return Long.parseLong(cookieTokens[1]);
        } catch (NumberFormatException nfe) {
            throw new InvalidCookieException(
                    "Cookie token[1] did not contain a valid number (contained '" + cookieTokens[1] + "')");
        }
    }

    protected Mono<Authentication> createSuccessfulAuthentication(ServerWebExchange exchange, UserDetails user) {
        return getKey().map(key -> new RememberMeAuthenticationToken(
                key, user, this.authoritiesMapper.mapAuthorities(user.getAuthorities())));
    }

    private boolean isValidCookieTokensLength(String[] cookieTokens) {
        return cookieTokens.length == 3 || cookieTokens.length == 4;
    }

    @Override
    public Mono<Void> loginFail(ServerWebExchange exchange) {
        log.debug("Interactive login attempt was unsuccessful.");
        cancelCookie(exchange);
        return parameterRequestCache.saveParameter(exchange, parameterName);

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Treat it as a bad cookie: the user re-authenticates and a correctly-formatted cookie is issued (handleError cancels the cookie automatically).
  2. If reproducible across many users, check whether a proxy/CDN is rewriting or truncating the cookie value.
  3. Verify you are not running mixed Halo versions that emit different token layouts.
  4. Ensure the cookie is not being URL-encoded twice in transit.
Defensive patterns

Strategy: try-catch

Try / catch

// Rely on TokenBasedRememberMeServices.handleError which cancels the cookie:
.onErrorResume(InvalidCookieException.class, ex -> {
    log.debug("Malformed remember-me cookie rejected: {}", ex.getMessage());
    return Mono.empty();
})

Prevention

When it happens

Trigger: A remember-me cookie whose decoded second colon-delimited token is non-numeric: a truncated, tampered, or manually-constructed cookie; a cookie produced by an incompatible/older cookie format; URL-decoding (URLDecoder.decode on each token) mangling the value. Reached via processAutoLoginCookie -> getTokenExpiryTime.

Common situations: Cookie altered by a browser extension or proxy; copy-paste of a cookie between users; downgrade/upgrade across a version that changed the token layout; locale-specific characters surviving into the token.

Related errors


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/0ad8ecf8baec0ce8. Report an issue: GitHub.