crowdsecurity/crowdsec · error

unable to create folder '%s': %w

Error message

unable to create folder '%s': %w

What it means

installScenarioCustomFrom copies a user-authored custom scenario into the test's runtime scenarios directory. Before copying it creates the destination folder (RuntimePath/scenarios/) with os.MkdirAll; failure to create that folder produces this error with the wrapped os cause. It signals a filesystem-level problem creating the runtime scenarios directory.

Source

Thrown at pkg/hubtest/scenario.go:55

	if err := os.Symlink(hubDirScenarioPath, scenarioDirParserPath); err != nil {
		if !os.IsExist(err) {
			return fmt.Errorf("unable to symlink scenario '%s' to '%s': %w", hubDirScenarioPath, scenarioDirParserPath, err)
		}
	}

	return nil
}

func (t *HubTestItem) installScenarioCustomFrom(scenario string, customPath string) (bool, error) {
	// we check if its a custom scenario
	customScenarioPath := filepath.Join(customPath, scenario)
	if _, err := os.Stat(customScenarioPath); os.IsNotExist(err) {
		return false, nil
	}

	itemTypeDirDest := fmt.Sprintf("%s/scenarios/", t.RuntimePath)
	if err := os.MkdirAll(itemTypeDirDest, os.ModePerm); err != nil {
		return false, fmt.Errorf("unable to create folder '%s': %w", itemTypeDirDest, err)
	}

	scenarioFileName := filepath.Base(customScenarioPath)

	scenarioFileDest := filepath.Join(itemTypeDirDest, scenarioFileName)
	if err := Copy(customScenarioPath, scenarioFileDest); err != nil {
		return false, fmt.Errorf("unable to copy scenario from '%s' to '%s': %w", customScenarioPath, scenarioFileDest, err)
	}

	return true, nil
}

func (t *HubTestItem) installScenarioCustom(scenario string) error {
	for _, customPath := range t.CustomItemsLocation {
		found, err := t.installScenarioCustomFrom(scenario, customPath)
		if err != nil {
			return err
		}

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the wrapped error (usually EACCES or ENOTDIR) and fix permissions on RuntimePath.
  2. Remove/rename any non-directory entry named 'scenarios' under RuntimePath.
  3. Ensure RuntimePath is set correctly in the test item and is writable by the running user.
  4. If running in a container, mount the runtime directory read-write.

Example fix

// before
RuntimePath: "/etc/crowdsec" // owned by root, test runs as user
// after
chown -R user:user /etc/crowdsec  # or point RuntimePath to a writable dir
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Stat(runtimePath); err != nil || !fi.IsDir() {
	return fmt.Errorf("runtime path %s is not a writable directory", runtimePath)
}
if err := unix.Access(runtimePath, unix.W_OK); err != nil {
	return fmt.Errorf("runtime path not writable: %w", err)
}

Try / catch

if err := os.MkdirAll(dest, os.ModePerm); err != nil {
	if os.IsPermission(err) {
		return fmt.Errorf("cannot create %s: check ownership/permissions: %w", dest, err)
	}
	return err
}

Prevention

When it happens

Trigger: installScenarioCustom -> installScenarioCustomFrom with an existing custom scenario file, where os.MkdirAll on '<runtime>/scenarios/' fails (permission denied, parent path is a file, read-only fs).

Common situations: RuntimePath points inside a read-only mount or a root-owned directory; a file named 'scenarios' exists where the directory should be; invalid characters in the path.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/57ef9c018cb86496. Report an issue: GitHub.