hyperledger/fabric · error

could not unmarshal CombinedPrincipal from principal

Error message

could not unmarshal CombinedPrincipal from principal

What it means

collectPrincipals wraps proto.Unmarshal failures when deserializing the principal.Principal payload into a CombinedPrincipal message, producing 'could not unmarshal CombinedPrincipal from principal: <cause>'. The principal was classified as COMBINED, but its opaque bytes are not a valid protobuf-encoded CombinedPrincipal.

Source

Thrown at msp/mspimpl.go:460

			return err
		}
	}
	return nil
}

// collectPrincipals collects principals from combined principals into a single MSPPrincipal slice.
func collectPrincipals(principal *m.MSPPrincipal, mspVersion MSPVersion) ([]*m.MSPPrincipal, error) {
	switch principal.PrincipalClassification {
	case m.MSPPrincipal_COMBINED:
		// Combined principals are not supported in MSP v1.0 or v1.1
		if mspVersion <= MSPv1_1 {
			return nil, errors.Errorf("invalid principal type %d", int32(principal.PrincipalClassification))
		}
		// Principal is a combination of multiple principals.
		principals := &m.CombinedPrincipal{}
		err := proto.Unmarshal(principal.Principal, principals)
		if err != nil {
			return nil, errors.Wrap(err, "could not unmarshal CombinedPrincipal from principal")
		}
		// Return an error if there are no principals in the combined principal.
		if len(principals.Principals) == 0 {
			return nil, errors.New("No principals in CombinedPrincipal")
		}
		// Recursively call msp.collectPrincipals for all combined principals.
		// There is no limit for the levels of nesting for the combined principals.
		var principalsSlice []*m.MSPPrincipal
		for _, cp := range principals.Principals {
			internalSlice, err := collectPrincipals(cp, mspVersion)
			if err != nil {
				return nil, err
			}
			principalsSlice = append(principalsSlice, internalSlice...)
		}
		// All the combined principals have been collected into principalsSlice
		return principalsSlice, nil
	default:

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect the wrapped cause; regenerate the principal via proto.Marshal on a properly populated &m.CombinedPrincipal{Principals: [...]}
  2. Verify the SDK/API used to build the policy constructs CombinedPrincipal, not another MSPPrincipal payload type
  3. Re-export/recreate the policy from the original toolchain instead of hand-editing serialized bytes
  4. Validate round-trip: proto.Unmarshal the payload before submitting the policy

Example fix

// before
principal := &m.MSPPrincipal{PrincipalClassification: m.MSPPrincipal_COMBINED, Principal: roleBytes} // wrong payload
// after
inner := &m.MSPPrincipal{PrincipalClassification: m.MSPPrincipal_ROLE,
    Principal: proto.MarshalTextString(...) /* properly marshaled MSPPrincipal */}
cpBytes, _ := proto.Marshal(&m.CombinedPrincipal{Principals: []*m.MSPPrincipal{inner, inner2}})
principal := &m.MSPPrincipal{PrincipalClassification: m.MSPPrincipal_COMBINED, Principal: cpBytes}
Defensive patterns

Strategy: validation

Validate before calling

cp := &m.CombinedPrincipal{}
if err := proto.Unmarshal(principal.Principal, cp); err != nil {
    return fmt.Errorf("principal payload is not a valid CombinedPrincipal: %w", err)
}
// proceed with the MSP call only after this passes

Type guard

func isValidCombinedPrincipalPayload(b []byte) bool {
    cp := &m.CombinedPrincipal{}
    return proto.Unmarshal(b, cp) == nil
}

Try / catch

ok, err := msp.SatisfiesPrincipal(id, principal)
if err != nil {
    if strings.Contains(err.Error(), "could not unmarshal CombinedPrincipal") {
        log.Errorf("malformed COMBINED principal payload: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling SatisfiesPrincipal/collectPrincipals with an MSPPrincipal whose PrincipalClassification is COMBINED but whose Principal bytes were built incorrectly — hand-marshaled bytes, bytes from a different message type (e.g. an MSPRole or OrganizationUnit), corrupted in transit, or an empty payload that fails unmarshal in the caller's proto version.

Common situations: Fabric SDK or tooling marshaling the wrong proto message into the COMBINED principal; policy files edited/re-serialized by external tools; byte corruption or truncation during policy transmission; mixing protobuf implementations with incompatible wire bytes.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


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