hyperledger/fabric · critical

failed to restore working directory: %s

Error message

failed to restore working directory: %s

What it means

moduleInfo chdirs into the chaincode path and defers a restore of the original working directory; if the restore chdir fails, it panics with 'failed to restore working directory: %s'. This is a hard safety failure to avoid leaving the process in the wrong directory.

Source

Thrown at core/chaincode/platforms/golang/platform.go:389

		return false, err
	default:
		return fi.Mode().IsRegular(), nil
	}
}

func moduleInfo(path string) (*ModuleInfo, error) {
	entryWD, err := os.Getwd()
	if err != nil {
		return nil, errors.Wrap(err, "failed to get working directory")
	}

	// directory doesn't exist so unlikely to be a module
	if err := os.Chdir(path); err != nil {
		return nil, nil
	}
	defer func() {
		if err := os.Chdir(entryWD); err != nil {
			panic(fmt.Sprintf("failed to restore working directory: %s", err))
		}
	}()

	// Using `go list -m -f '{{ if .Main }}{{.GoMod}}{{ end }}' all` may try to
	// generate a go.mod when a vendor tool is in use. To avoid that behavior
	// we use `go env GOMOD` followed by an existence check.
	cmd := exec.Command("go", "env", "GOMOD")
	cmd.Env = os.Environ()
	output, err := cmd.Output()
	if err != nil {
		return nil, wrapExitErr(err, "failed to determine module root")
	}

	modExists, err := regularFileExists(strings.TrimSpace(string(output)))
	if err != nil {
		return nil, err
	}
	if !modExists {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure the peer's original working directory remains mounted and exists during chaincode packaging.
  2. Avoid deleting temp/mount directories concurrently with packaging operations.
  3. Run the peer from a stable directory (e.g. /etc/hyperledger/fabric) rather than ephemeral paths.
Defensive patterns

Strategy: try-catch

Validate before calling

wd, err := os.Getwd()
if err != nil { return err }
if _, err := os.Stat(wd); err != nil { return fmt.Errorf("cwd will be unchdir-able: %w", err) }

Try / catch

// moduleInfo panics on restore failure; guard at a higher level
func safeDescribe(path string) (out *golang.CodeDescriptor, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("moduleInfo panic: %v", r)
		}
	}()
	return golang.DescribeCode(path)
}

Prevention

When it happens

Trigger: The entry working directory captured by os.Getwd is deleted or becomes inaccessible while moduleInfo is executing inside the chaincode path, so the deferred os.Chdir(entryWD) fails and panics.

Common situations: Concurrent cleanup deleting the peer's original cwd, containers churning tmpfs mounts, race between packaging and tmp dir removal.

Related errors


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