hyperledger/fabric · warning

bad normal message: %s

Error message

bad normal message: %s

What it means

Returned by BFTChain.Order when the normal (transaction) message fails re-validation against the current config. If configSeq has fallen behind the chain's actual config sequence, ProcessNormalMsg is re-run and its error is surfaced as 'bad normal message'. The message is rejected and never enters consensus.

Source

Thrown at orderer/consensus/smartbft/chain.go:337

	}

	c.Logger.Debugf("Consensus.SubmitRequest, node id %d", c.Config.SelfID)
	if err = c.consensus.SubmitRequest(reqBytes); err != nil {
		return errors.Wrapf(err, "failed to submit request")
	}
	return nil
}

// Order accepts a message which has been processed at a given configSeq.
// If the configSeq advances, it is the responsibility of the consenter
// to revalidate and potentially discard the message
// The consenter may return an error, indicating the message was not accepted
func (c *BFTChain) Order(env *cb.Envelope, configSeq uint64) error {
	seq := c.support.Sequence()
	if configSeq < seq {
		c.Logger.Warnf("Normal message was validated against %d, although current config seq has advanced (%d)", configSeq, seq)
		if _, err := c.support.ProcessNormalMsg(env); err != nil {
			return errors.Errorf("bad normal message: %s", err)
		}
	}

	return c.submit(env)
}

// Configure accepts a message which reconfigures the channel and will
// trigger an update to the configSeq if committed.  The configuration must have
// been triggered by a ConfigUpdate message. If the config sequence advances,
// it is the responsibility of the consenter to recompute the resulting config,
// discarding the message if the reconfiguration is no longer valid.
// The consenter may return an error, indicating the message was not accepted
func (c *BFTChain) Configure(config *cb.Envelope, configSeq uint64) error {
	if err := c.verifier.ConfigValidator.ValidateConfig(config); err != nil {
		return err
	}
	seq := c.support.Sequence()
	if configSeq < seq {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Have the client fetch the latest config seq (re-deliver/reconnect) and resubmit with an up-to-date configSeq
  2. Fix the client so it does not send config transactions via the normal Order path (use Configure)
  3. Read the inner %s text from ProcessNormalMsg (e.g. invalid tx, mvcc conflict) and correct the transaction accordingly
  4. Retry with a fresh envelope after re-validating against current channel config

Example fix

// before
chain.Order(staleEnv, oldConfigSeq) // -> bad normal message: ...

// after
if err := chain.Order(env, currentSeq); err != nil && strings.Contains(err.Error(), "bad normal message") {
    env = rebuildEnvelope(tx) // re-create tx against current channel config
    if err := chain.Order(env, support.Sequence()); err != nil { return err }
}
Defensive patterns

Strategy: validation

Validate before calling

seq := chain.Sequence() // via support/metadata
if clientConfigSeq < seq {
    // re-fetch/re-validate the tx against current config before submitting
    env = revalidateNormalMsg(env)
    clientConfigSeq = seq
}
return chain.Order(env, clientConfigSeq)

Try / catch

if err := chain.Order(env, configSeq); err != nil {
    if strings.Contains(err.Error(), "bad normal message") {
        // refresh config seq and resubmit a freshly validated envelope
        return retryWithFreshConfig(env)
    }
    return err
}

Prevention

When it happens

Trigger: SendTx calls Order(env, configSeq) with a configSeq older than c.support.Sequence() (config has advanced since last delivery), AND the re-processed envelope fails ProcessNormalMsg — e.g. it is malformed, is actually a config tx, or fails mvcc/version verification.

Common situations: A config update committed while a client's transaction was in flight, invalidating the seq the tx was validated against; clients resubmitting stale transactions after a channel reconfiguration; sending config-update envelopes through the normal tx path.

Related errors


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