hyperledger/fabric · error

could not read directory %s

Error message

could not read directory %s

What it means

getPemMaterialFromDir lists a certificate directory with os.ReadDir and fails when the directory cannot be read — it does not exist, is a file instead of a directory, or lacks permissions. The error wraps the OS error with the directory path.

Source

Thrown at msp/configbuilder.go:94

	if b == nil { // TODO: also check that the type is what we expect (cert vs key..)
		return nil, errors.Errorf("no pem content for file %s", file)
	}

	return bytes, nil
}

func getPemMaterialFromDir(dir string) ([][]byte, error) {
	mspLogger.Debugf("Reading directory %s", dir)

	_, err := os.Stat(dir)
	if os.IsNotExist(err) {
		return nil, err
	}

	content := make([][]byte, 0)
	files, err := os.ReadDir(dir)
	if err != nil {
		return nil, errors.Wrapf(err, "could not read directory %s", dir)
	}

	for _, f := range files {
		fullName := filepath.Join(dir, f.Name())

		f, err := os.Stat(fullName)
		if err != nil {
			mspLogger.Warningf("Failed to stat %s: %s", fullName, err)
			continue
		}
		if f.IsDir() {
			continue
		}

		mspLogger.Debugf("Inspecting file %s", fullName)

		item, err := readPemFile(fullName)
		if err != nil {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Confirm the directory exists and is a directory: 'ls -ld <dir>'; correct CORE_PEER_MSPCONFIGPATH or the dir argument
  2. Point the config at the MSP root (the dir containing signcerts/, cacerts/, etc.), not a cert file
  3. Fix permissions: ensure the running user can read/traverse every path component
  4. In containers, verify the volume mount for the MSP directory is present and correct

Example fix

// before
GetLocalMspConfig("/etc/hyperledger/fabric/msp/signcerts", ...) // wrong: file dir
// after: use MSP root
GetLocalMspConfig("/etc/hyperledger/fabric/msp", bccspConfig, "Org1MSP")
Defensive patterns

Strategy: validation

Validate before calling

func mspLayoutOk(root string) error {
    for _, d := range []string{"signcerts", "cacerts", "admincerts", "keystore"} {
        fi, err := os.Stat(filepath.Join(root, d))
        if err != nil { return fmt.Errorf("missing %s under %s: %w", d, root, err) }
        if !fi.IsDir() { return fmt.Errorf("%s under %s is not a directory", d, root) }
    }
    return nil
}

Try / catch

if err := InitCrypto(bsp, mspPath, mspID); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && os.IsNotExist(err) {
        log.Fatalf("MSP dir %s not found: fix CORE_PEER_MSPCONFIGPATH or mount", pe.Path)
    }
    return err
}

Prevention

When it happens

Trigger: GetLocalMspConfig/getMspConfig calling getPemMaterialFromDir on signcerts/cacerts/admincerts/keystore paths when CORE_PEER_MSPCONFIGPATH points to a nonexistent or wrong-structure directory; getIdentity in idemix reading a missing dir.

Common situations: MSP path typo in peer/orderer config, MSP volume not mounted in a container, pointing at a single file rather than the MSP root directory, running as a user without execute permission on parent dirs.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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