Bug: POST /entries?waitForCommit=true logs a spurious 303 See Other at the POSTCOMMIT stage
Summary
For SCRAPI v9 clients (api-version=2026-03-26) submitting with waitForCommit=true, the service logs a 303 See Other response for every registration, even though the client correctly receives 201 Created with the receipt. The 303 is an intermediate status set by the locally-committed handler that is later overwritten by the consensus-committed handler — but the logging (tracing) captures the intermediate value, making the logs misleading.
How it appears
In the node logs, each /entries submission with waitForCommit=true produces a POSTCOMMIT trace line with Status=303:
::END:: Stage=MAIN Verb=POST Path=/entries Query=...&waitForCommit=true Status=200 TxId=2.75 ...
::END:: Stage=POSTCOMMIT Verb=POST Path=/entries Query=...&waitForCommit=true Status=303 TxId=2.75 ...
There is no follow-up log line showing the real 201, so it looks like the client got a 303 when it actually got 201.
Root cause
Two response-producing callbacks run for the same request:
- Locally-committed handler
operation_locally_committed_func runs first and, for any SCRAPI v9 request, unconditionally sets 303 See Other with Location: /entries/{txid} — it does not check waitForCommit.
- Consensus-committed handler (registered via
set_consensus_committed_function, only when waitForCommit=true) runs later on global commit and overwrites the status to 201 Created with the embedded receipt before the response is actually sent.
The tracing wrapper tracing_adapter_last logs rpc_ctx->get_response_status() at the end of the local-commit stage — capturing the 303. The later 201 override happens in an untraced commit callback, so it never appears in the logs.
Impact
- Cosmetic/observability only — clients receive the correct
201. But the logs are misleading for anyone debugging registration flows or building log-based monitoring/alerts.
- Minor wasted work: the 303 status/
Location header are set and immediately overwritten on every waitForCommit submission.
- Edge cases where the 303 could actually leak to the client: if
build_receipt_for_committed_tx returns null (the consensus handler returns early, leaving 303) or the tx is Invalid (sets 503).
Files responsible
app/src/operations_endpoints.h — operation_locally_committed_func: sets HTTP_STATUS_SEE_OTHER (303) for SCRAPI v9 without checking waitForCommit.
app/src/main.cpp — the /entries endpoint registers operation_locally_committed_func as the locally-committed handler and installs the consensus-committed handler (set_consensus_committed_function) only for waitForCommit; the 201 override lives there.
app/src/tracing.h — tracing_adapter_last logs the response status at local-commit time, capturing the intermediate 303.
Bug:
POST /entries?waitForCommit=truelogs a spurious303 See Otherat the POSTCOMMIT stageSummary
For SCRAPI v9 clients (
api-version=2026-03-26) submitting withwaitForCommit=true, the service logs a303 See Otherresponse for every registration, even though the client correctly receives201 Createdwith the receipt. The 303 is an intermediate status set by the locally-committed handler that is later overwritten by the consensus-committed handler — but the logging (tracing) captures the intermediate value, making the logs misleading.How it appears
In the node logs, each
/entriessubmission withwaitForCommit=trueproduces a POSTCOMMIT trace line withStatus=303:There is no follow-up log line showing the real
201, so it looks like the client got a 303 when it actually got 201.Root cause
Two response-producing callbacks run for the same request:
operation_locally_committed_funcruns first and, for any SCRAPI v9 request, unconditionally sets 303 See Other withLocation: /entries/{txid}— it does not checkwaitForCommit.set_consensus_committed_function, only whenwaitForCommit=true) runs later on global commit and overwrites the status to 201 Created with the embedded receipt before the response is actually sent.The tracing wrapper
tracing_adapter_lastlogsrpc_ctx->get_response_status()at the end of the local-commit stage — capturing the 303. The later 201 override happens in an untraced commit callback, so it never appears in the logs.Impact
201. But the logs are misleading for anyone debugging registration flows or building log-based monitoring/alerts.Locationheader are set and immediately overwritten on everywaitForCommitsubmission.build_receipt_for_committed_txreturns null (the consensus handler returns early, leaving 303) or the tx isInvalid(sets 503).Files responsible
app/src/operations_endpoints.h—operation_locally_committed_func: setsHTTP_STATUS_SEE_OTHER(303) for SCRAPI v9 without checkingwaitForCommit.app/src/main.cpp— the/entriesendpoint registersoperation_locally_committed_funcas the locally-committed handler and installs the consensus-committed handler (set_consensus_committed_function) only forwaitForCommit; the 201 override lives there.app/src/tracing.h—tracing_adapter_lastlogs the response status at local-commit time, capturing the intermediate 303.