crowdsecurity/crowdsec · error

unable to create folder '%s': %w

Error message

unable to create folder '%s': %w

What it means

After validating the stage, installPostoverflowCustomFrom creates the destination stage directory under the test runtime path with os.MkdirAll. Failure to create it (permission denied, path is a file, invalid characters) is wrapped with the target directory path and aborts the custom postoverflow install.

Source

Thrown at pkg/hubtest/postoverflow.go:67

	customPostOverflowPath := filepath.Join(customPath, postoverflow)
	if _, err := os.Stat(customPostOverflowPath); os.IsNotExist(err) {
		return false, nil
	}

	customPostOverflowPathSplit := strings.Split(customPostOverflowPath, "/")
	customPostoverflowName := customPostOverflowPathSplit[len(customPostOverflowPathSplit)-1]
	// because path is postoverflows/<stage>/<author>/parser.yaml and we wan't the stage
	customPostoverflowStage := customPostOverflowPathSplit[len(customPostOverflowPathSplit)-3]

	// check if stage exist
	hubStagePath := filepath.Join(t.HubPath, fmt.Sprintf("postoverflows/%s", customPostoverflowStage))
	if _, err := os.Stat(hubStagePath); os.IsNotExist(err) {
		return false, fmt.Errorf("stage '%s' from extracted '%s' doesn't exist in the hub", customPostoverflowStage, hubStagePath)
	}

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

	customPostoverflowDest := filepath.Join(stageDirDest, customPostoverflowName)
	// if path to postoverflow exist, copy it
	if err := Copy(customPostOverflowPath, customPostoverflowDest); err != nil {
		return false, fmt.Errorf("unable to copy custom parser '%s' to '%s': %w", customPostOverflowPath, customPostoverflowDest, err)
	}

	return true, nil
}

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

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the wrapped MkdirAll error for the OS cause (EACCES/ENOTDIR)
  2. Verify t.RuntimePath exists, is writable, and contains no file blocking the stage path
  3. Remove the conflicting file at <runtime>/postoverflows/<stage> and re-run
  4. Run the tests with sufficient filesystem permissions
Defensive patterns

Strategy: try-catch

Validate before calling

if err := os.MkdirAll(t.RuntimePath, 0o755); err != nil {
    return fmt.Errorf("runtime path unusable: %w", err)
}

Try / catch

if err := t.installPostoverflowCustom(p); err != nil {
    var perr *os.PathError
    if errors.As(err, &perr) {
        log.Errorf("mkdir failed for %s: %v", perr.Path, perr.Err)
    }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll(stageDirDest, os.ModePerm) fails because t.RuntimePath/postoverflows/<stage> cannot be created: runtime path points into a read-only tree, a file occupies a path component, or RuntimePath is empty/invalid.

Common situations: Test runtime directory on a read-only mount; leftover regular file where a directory is expected; RuntimePath misconfigured in the test definition.

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/cbd67cb8c6822efc. Report an issue: GitHub.