hyperledger/fabric · critical

transaction %d in block %d has skipped validation

Error message

transaction %d in block %d has skipped validation

What it means

After validating a block, the validator asserts that every transaction received a validation flag. If any transaction still has TxValidationCode_NOT_VALIDATED, internal bookkeeping failed, so the whole block validation returns this error instead of committing a partially validated block.

Source

Thrown at core/committer/txvalidator/v14/validator.go:244

	}

	// Initialize metadata structure
	protoutil.InitBlockMetadata(block)

	block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsfltr

	elapsedValidation := time.Since(startValidation) / time.Millisecond // duration in ms
	logger.Infof("[%s] Validated block [%d] in %dms", v.ChannelID, block.Header.Number, elapsedValidation)

	return nil
}

// allValidated returns error if some of the validation flags have not been set
// during validation
func (v *TxValidator) allValidated(txsfltr txflags.ValidationFlags, block *common.Block) error {
	for id, f := range txsfltr {
		if peer.TxValidationCode(f) == peer.TxValidationCode_NOT_VALIDATED {
			return errors.Errorf("transaction %d in block %d has skipped validation", id, block.Header.Number)
		}
	}

	return nil
}

func markTXIdDuplicates(txids []string, txsfltr txflags.ValidationFlags) {
	txidMap := make(map[string]struct{})

	for id, txid := range txids {
		if txid == "" {
			continue
		}

		_, in := txidMap[txid]
		if in {
			logger.Error("Duplicate txid", txid, "found, skipping")
			txsfltr.SetFlag(id, peer.TxValidationCode_DUPLICATE_TXID)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Identify which validator (VSCC plugin) handled the transaction and why it didn't set a flag; check peer logs for preceding errors
  2. Fix or replace the custom validation plugin so it always returns a validation code
  3. Upgrade the peer to the latest patch release in case of a known validator bug
  4. Isolate the offending block/transaction and reprocess or refetch the block from the ordering service

Example fix

// before: plugin returns without setting code
func (p *MyPlugin) Validate(...) error { if bad { return errors.New("x") } ... }
// after
// return a proper validation code via the common errors mechanism
return errors.WithCommonValidationCode(errors.New("x"))
Defensive patterns

Strategy: type-guard

Validate before calling

// after custom validation, verify all flags are set
for _, f := range txsfltr {
    if peer.TxValidationCode(f) == peer.TxValidationCode_NOT_VALIDATED {
        return errors.New("unset validation flag")
    }
}

Type guard

func allFlagsSet(flags txflags.ValidationFlags) bool {
    for _, f := range flags {
        if peer.TxValidationCode(f) == peer.TxValidationCode_NOT_VALIDATED { return false }
    }
    return true
}

Try / catch

if err := validator.Validate(block); err != nil && strings.Contains(err.Error(), "has skipped validation") {
    // halt commit pipeline, inspect plugin/validator, do not commit the block
}

Prevention

When it happens

Trigger: allValidated (called from Validate) finds a flag in txsfltr equal to NOT_VALIDATED after the per-transaction validation loop — a validator path failed to set a commit/validation code for that transaction.

Common situations: Custom validation plugin returning without setting a validation code; internal Fabric bug in a validation path; corrupted/malformed block causing a validation branch to skip flag assignment.

Related errors


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