errorsyntaxPOLksef

KSEF-21170:KSeF interactive session has expired

Fix: Detect 21170, discard the expired session token, run a fresh authentication challenge, and replay the failed request under the new session. Add proactive session refresh before the documented lifetime elapses.

KSeF error 21170 ("Sesja interaktywna wygasła") is returned when the caller uses a session token whose validity window has elapsed. Interactive sessions have a bounded lifetime set by the Ministry of Finance (currently 2 hours from InitSession, refreshed by activity), and once expired the session cannot be resumed — a fresh authentication challenge is required.

Severity
Fatal
Rule set
ksef
Country
POL
Fix type
BLOCKED
Confidence
95%
Category
session-management

Engine Classification

Financial or legal field · Modification blocked by policy

What is KSEF-21170?

KSEF-21170 is a fatal validation rule defined in the ksef specification (POL national rules). It validates the InitToken again. element under Session > *). Interactive sessions carry a session token in the SessionToken header and are subject to both an absolute lifetime and an idle timeout. When either boundary is crossed, subsequent calls with that token return HTTP 401 and exceptionCode 21170. The session cannot be extended after expiry — the client must run AuthorisationChallenge → InitSigned in the UBL invoice XML.

When this rule fires, the invoice is rejected by Peppol access points and never reaches the buyer.

Target path: KSeF sessions come in two shapes: interactive (/online/Session/InitSigned or InitToken) and batch (/batch/Session/*). Interactive sessions carry a session token in the SessionToken header and are subject to both an absolute lifetime and an idle timeout. When either boundary is crossed, subsequent calls with that token return HTTP 401 and exceptionCode 21170. The session cannot be extended after expiry — the client must run AuthorisationChallenge → InitSigned/InitToken again.

This error requires manual correction — financial fields are protected by policy.

Why This Error Matters

Session expiry is the single most common cause of "KSeF integration flakiness" reports during ERP rollouts. Long-running batch jobs, overnight queue workers, and manual test sessions all hit 21170 without warning. Clients that treat 21170 as a fatal error rather than a recoverable one cause user-visible submission failures for what should be a transparent housekeeping issue.

KSEF-21170 is a hard failure — the invoice must be corrected and re-sent before it can reach the recipient.

Interrupts in-flight batch jobs and can cause partial submissions if error handling is naive. With correct recovery, impact is limited to a few seconds of latency per session refresh.

Validator Behavior

  • ·Causes invoice rejection
  • ·Error returned: KSEF-21170
  • ·Specification: ksef

How to Fix It

1.

2.

3.

4.

5.

6.

XML Example

Generic example based on the rule's target XPath. Your actual XML structure may differ.

Before
<!-- Triggers validation error -->
<InitToken again.></InitToken again.>
After
<!-- Corrected -->
<InitToken again.>VALID_VALUE</InitToken again.>

Technical Reference

XPathKSeF sessions come in two shapes: interactive (/online/Session/InitSigned or InitToken) and batch (/batch/Session/*). Interactive sessions carry a session token in the SessionToken header and are subject to both an absolute lifetime and an idle timeout. When either boundary is crossed, subsequent calls with that token return HTTP 401 and exceptionCode 21170. The session cannot be extended after expiry — the client must run AuthorisationChallenge → InitSigned/InitToken again.
Specksef
StrategyClient-side session lifecycle management. Invoice Navigator handles session refresh transparently — callers see one long-lived credential and never touch KSeF session tokens directly.

Code Example

class KsefClient {
  async call(method, path, body) {
    if (!this.session || this.sessionAgeMs() > 90 * 60 * 1000) {
      await this.refreshSession();
    }
    try {
      return await this.rawCall(method, path, body, this.session.token);
    } catch (err) {
      if (err.exceptionCode === 21170) {
        await this.refreshSession();
        return this.rawCall(method, path, body, this.session.token);
      }
      throw err;
    }
  }
}

Common Causes

  • ·Long-running batch job holds a session for over 2 hours without refresh.
  • ·Overnight queue worker holds a session token across low-activity periods and hits the idle timeout.
  • ·Manual testing session left open between developer breaks.
  • ·Session cached in a shared credential store and reused after expiry.
  • ·Clock skew — client tracks session age from local clock while KSeF tracks from server timestamp.

Seeing this in production? The API handles KSEF-21170 automatically. See the fix response →

Commonly Seen In

All KSeF integrationsKSeF Taxpayer Application

Frequently Asked Questions

The Ministry of Finance documents a 2-hour absolute lifetime for interactive sessions with an activity-based refresh window. In practice, plan for a hard 2-hour ceiling and re-authenticate proactively at ~90 minutes.

No — there is no session-extend endpoint. Once you have a session token, its expiry is fixed. The only way to extend is to run AuthorisationChallenge again and start a new session.

No — 21170 is a normal lifecycle event, not a security event. Discard the token and re-authenticate. Compromised tokens surface as 21302 (Token nieaktywny) or 21303 (Token unieważniony).

No — AuthorisationChallenge is rate-limited (see KSEF-21121) and re-authenticating per request will hit that quota fast. Use one session per worker and refresh at 90 minutes.

Yes — Invoice Navigator exposes long-lived API keys to your ERP and manages KSeF session lifecycle internally, including 21170 recovery, proactive refresh, and per-context session pooling.

Related Errors

Related Content

Last updated: 28 July 2026

Share this guide:

Validate your invoice

Drop your XML here to check for KSEF-21170

Detect KSEF-21170 before submission

This error involves a financial field that can't be auto-modified. We'll flag it with a clear diagnosis so you can fix it at the source.