binarywang/WxJava · warning · IllegalStateException

getAttributeNames: Session already invalidated

Error message

getAttributeNames: Session already invalidated

What it means

StandardSession.getAttributeNames throws IllegalStateException if the session is no longer valid (invalidated or expired). This mirrors servlet-container session semantics: once isValidInternal() is false, any attribute access is forbidden. The session is used internally by message routers (e.g. WxMpMessageRouter) to track per-user state.

Source

Thrown at weixin-java-common/src/main/java/me/chanjar/weixin/common/session/StandardSession.java:95

  @Override
  public Object getAttribute(String name) {

    if (!isValidInternal()) {
      throw new IllegalStateException
        (SM.getString("sessionImpl.getAttribute.ise"));
    }

    if (name == null) {
      return null;
    }

    return this.attributes.get(name);
  }

  @Override
  public Enumeration<String> getAttributeNames() {
    if (!isValidInternal()) {
      throw new IllegalStateException(SM.getString("sessionImpl.getAttributeNames.ise"));
    }

    Set<String> names = new HashSet<>();
    names.addAll(this.attributes.keySet());
    return Collections.enumeration(names);
  }

  @Override
  public void setAttribute(String name, Object value) {
    // Name cannot be null
    if (name == null) {
      throw new IllegalArgumentException(SM.getString("sessionImpl.setAttribute.namenull"));
    }

    // Null value is the same as removeAttribute()
    if (value == null) {
      removeAttribute(name);
      return;

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Call session.isValid() (or the router's validity check) before reading attributes.
  2. Discard session references after invalidate() and re-acquire a fresh session from the manager.
  3. Tune maxInactiveInterval to match your handler's lifetime if timeouts happen mid-flow.
  4. Catch IllegalStateException around post-invalidate cleanup and treat it as 'no attributes'.

Example fix

// before
Enumeration<String> names = session.getAttributeNames(); // throws if expired

// after
if (session.isValid()) {
  Enumeration<String> names = session.getAttributeNames();
} else {
  names = Collections.emptyEnumeration();
}
Defensive patterns

Strategy: validation

Validate before calling

if (session.isValid()) {
  Enumeration<String> names = session.getAttributeNames();
} else {
  names = Collections.emptyEnumeration();
}

Type guard

private static boolean sessionAccessible(WxSession s) {
  return s != null && s.isValid();
}

Try / catch

try {
  return session.getAttributeNames();
} catch (IllegalStateException e) {
  // session expired/invalidated — treat as empty
  return Collections.emptyEnumeration();
}

Prevention

When it happens

Trigger: Calling session.getAttributeNames() after session.invalidate() was called, or after the session expired past its maxInactiveInterval.

Common situations: A message-router handler retains a WxSession reference and reads attributes after the session timed out; explicit invalidate() followed by a cleanup/access pass; long-lived async work holding a stale session.

Related errors


AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14). Data as JSON: /api/errors/f9126491d42a75b9. Report an issue: GitHub.