Skip to content

ui/import: an expired outbound bearer makes the status poll 401 and the page marks a still-running submission as failed / finished with 0 files #1561

Description

@angela-helios

Summary

The Import page polls the recipient's GET /bulk-submit-status/{id} with the static HFS_OUTBOUND_BEARER_TOKEN. When that token expires mid-import (Keycloak's shipped realm gives it 300 s), the next poll answers 401 and the page marks the submission failed and stops polling for good, while the recipient — the same HFS process — keeps ingesting to completion. The card then reads Result · Processing finished at <time of the 401> · Output files 0 · Error files 0 · Failed, which is false on every count: the ingest is neither finished nor failed, and its files are still being written.

Environment

main 0eb99c238, HFS_STORAGE_BACKEND=sqlite-es, release build, Keycloak 26.1.5 with the repo realm.json (accessTokenLifespan 300), HFS_AUTH_ENABLED=true, HFS_OUTBOUND_BEARER_TOKEN=$(./docker/keycloak/get-token.sh) minted at 21:33:52Z, no interactive login. Submission created from the Import page (auth=none) at 21:33:56Z for the full 18.96 M Synthea corpus (#1171 T3).

What happens

Submission log on /ui/bulk-import/3ad87fb2-e899-422a-9574-41fc2063488a, newest first:

2026-09-28T21:41:07.810Z  Status poll answered 401; polling stopped and the submission is marked failed.
2026-09-28T21:39:07.547Z  Status: Processing 4% - 702,191 Resources written
2026-09-28T21:37:07.514Z  Status: Processing 2% - 510,391 Resources written
2026-09-28T21:34:22.483Z  Status: Processing 0% - 170,891 Resources written
2026-09-28T21:33:56.368Z  Status: Queued - starting shortly
2026-09-28T21:33:56.350Z  Bulk status kick-off request
2026-09-28T21:33:56.349Z  Manifest accepted by the recipient (200).

Status card afterwards: Result — Processing finished at 2026-09-28T21:41:07.810Z, Output files 0, Error files 0, summary Status: Failed.

Server log, the poll that killed it (token exp 21:38:52Z; the 21:39:07 poll still passed inside the clock-skew leeway):

DEBUG request{method=GET uri=/bulk-submit-status/7fb981dd-ecb7-4b66-873d-82af27ab7e10}: tower_http::trace::on_response: finished processing request latency=0 ms status=401

Meanwhile the recipient is fine — GET /bulk-submit-status/7fb981dd-… with a freshly minted bearer a minute later:

HTTP/1.1 202 Accepted
x-progress: Processing 5% - 926,391 Resources written
retry-after: 120

(202 = still in progress, per the Bulk Data async pattern)
and the ingest goes on (the sample at 21:41 already had 925 MB in hfs.db and 8.3 M Elasticsearch documents; it is still running as this is filed).

Expected

A 401 on the status poll is a credential problem of the page, not a result of the submission. Either the poll re-mints / refreshes its bearer (the Import page already knows how to obtain one for auth=backend-services; for auth=none with HFS_OUTBOUND_BEARER_TOKEN a static token cannot be refreshed, so at least keep polling with backoff and say status unavailable: outbound token rejected (401) instead of a terminal Failed), or the card must not claim Processing finished at / Failed for a submission whose recipient never reported either. The same applies to a token that is revoked or rotated.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions