hyperledger/fabric · error

envelope timestamp %s is more than %s apart from current ser

Error message

envelope timestamp %s is more than %s apart from current server time %s

What it means

validateChannelHeader compares the envelope timestamp to server time; if the absolute difference exceeds the handler's configured TimeWindow the request is rejected. This prevents replaying old SeekInfo envelopes and bounds clock-skew-sensitive authorization (context binding).

Source

Thrown at common/deliver/deliver.go:401

	err = h.validateChannelHeader(ctx, chdr)
	if err != nil {
		return nil, nil, nil, err
	}

	return payload, chdr, shdr, nil
}

func (h *Handler) validateChannelHeader(ctx context.Context, chdr *cb.ChannelHeader) error {
	if chdr.GetTimestamp() == nil {
		err := errors.New("channel header in envelope must contain timestamp")
		return err
	}

	envTime := time.Unix(chdr.GetTimestamp().Seconds, int64(chdr.GetTimestamp().Nanos)).UTC()
	serverTime := time.Now()

	if math.Abs(float64(serverTime.UnixNano()-envTime.UnixNano())) > float64(h.TimeWindow.Nanoseconds()) {
		err := errors.Errorf("envelope timestamp %s is more than %s apart from current server time %s", envTime, h.TimeWindow, serverTime)
		return err
	}

	err := h.BindingInspector.Inspect(ctx, chdr)
	if err != nil {
		return err
	}

	return nil
}

func noExpiration(_ []byte) time.Time {
	return time.Time{}
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Synchronize the client machine's clock with NTP (chrony/ntpd or host time sync for containers).
  2. Re-sign and send the deliver request immediately before dispatch, not ahead of time.
  3. Increase the orderer's deliver TimeWindow configuration if the deployment legitimately tolerates larger skew.
  4. Compare client clock to orderer (e.g. orderer health/log timestamps) to quantify the skew.

Example fix

// before (client signs at script start, sends later)
timestamp := scriptStartTime

// after (sign just before send, with synced clock)
runNtpSync()
timestamp := protoutil.CurrentTimestampBytes()
env, _ := protoutil.CreateEnvelope(...); deliverNow(env)
Defensive patterns

Strategy: retry

Validate before calling

skew := time.Since(time.Unix(chdr.GetTimestamp().Seconds, int64(chdr.GetTimestamp().Nanos)).UTC())
if skew < 0 { skew = -skew }
if skew > 15*time.Minute { resyncClockAndResignEnvelope() }

Try / catch

for attempt := 0; attempt < 2; attempt++ {
    err := sendDeliverRequest(env)
    if err != nil && strings.Contains(err.Error(), "apart from current server time") {
        syncClock(); env = resignWithFreshTimestamp(); continue
    }
    return err
}

Prevention

When it happens

Trigger: Client clock is off (ahead or behind) by more than TimeWindow (default 15m) when the deliver request is signed and sent; a delayed/queued request that exceeds the window; a replayed captured envelope.

Common situations: VMs/containers with drifting clocks and no NTP; signing a request long before sending (batch scripts); cross-timezone/local-time bugs when computing timestamps in custom clients.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/daadd619817238c1. Report an issue: GitHub.