ory/kratos · error

webhook response body could not be read

Error message

webhook response body could not be read

What it means

The webhook returned HTTP 200 and the courier tried to read its body through the pre-limited reader, but io.ReadAll failed. This is an I/O-level failure while streaming the response (connection reset mid-body, read timeout), not a content problem.

Solutions

  1. Retry the flow - transient network truncation is the most common cause
  2. Check for proxies or load balancers that cut long-lived response bodies
  3. Verify the webhook endpoint closes responses cleanly
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at selfservice/hook/web_hook.go:468 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/c92a9771b6974563. Report an issue: GitHub.

Appendix: source

Thrown at selfservice/hook/web_hook.go:468

		}
	}
	return res
}

func parseWebhookResponse(resp *http.Response, id *identity.Identity) (err error) {
	if resp == nil {
		return errors.Errorf("empty response provided from the webhook")
	}

	if resp.StatusCode == http.StatusOK {
		type localIdentity identity.Identity
		var hookResponse struct {
			Identity *localIdentity `json:"identity"`
		}
		// io.ReadAll is safe, because resp.Body is already a limited reader.
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return errors.Wrap(err, "webhook response body could not be read")
		}
		if err = json.Unmarshal(body, &hookResponse); err != nil {
			return errors.Wrap(err, "webhook response could not be unmarshalled properly from JSON")
		}

		if hookResponse.Identity == nil {
			return nil
		}

		if len(hookResponse.Identity.Traits) > 0 {
			id.Traits = hookResponse.Identity.Traits
		}

		if len(hookResponse.Identity.SchemaID) > 0 {
			id.SchemaID = hookResponse.Identity.SchemaID
		}

		if len(hookResponse.Identity.State) > 0 {

View on GitHub (pinned to b86338da04)