crowdsecurity/crowdsec · error

unable to copy '%s' to '%s': %w

Error message

unable to copy '%s' to '%s': %w

What it means

installScenarioItem copies the scenario file from the hub directory (RuntimeHubPath) into the test's runtime hub scenarios directory. If the file copy fails (Copy wraps os-level create/read/copy errors), this error reports both source and destination paths plus the underlying cause. Typical causes are missing directories, permission problems, or the source file not existing.

Source

Thrown at pkg/hubtest/scenario.go:32

		return fmt.Errorf("can't get absolute path of '%s': %w", sourcePath, err)
	}

	sourceFilename := filepath.Base(sourcePath)

	// runtime/hub/scenarios/crowdsecurity/
	hubDirScenarioDest := filepath.Join(t.RuntimeHubPath, filepath.Dir(item.RemotePath))

	// runtime/parsers/scenarios/
	itemTypeDirDest := fmt.Sprintf("%s/scenarios/", t.RuntimePath)

	if err := createDirs([]string{hubDirScenarioDest, itemTypeDirDest}); err != nil {
		return err
	}

	// runtime/hub/scenarios/crowdsecurity/ssh-bf.yaml
	hubDirScenarioPath := filepath.Join(hubDirScenarioDest, sourceFilename)
	if err := Copy(sourcePath, hubDirScenarioPath); err != nil {
		return fmt.Errorf("unable to copy '%s' to '%s': %w", sourcePath, hubDirScenarioPath, err)
	}

	// runtime/scenarios/ssh-bf.yaml
	scenarioDirParserPath := filepath.Join(itemTypeDirDest, sourceFilename)
	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

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the wrapped error to identify whether the source is missing or the destination is unwritable.
  2. Re-download the hub: 'cscli hub update' then re-run the test.
  3. Fix permissions/ownership on the runtime hub directory (or run as the right user).
  4. Ensure the parent destination directory exists before Copy (MkdirAll was done earlier; verify it succeeded).

Example fix

// before
if err := Copy(sourcePath, hubDirScenarioPath); err != nil {
	return fmt.Errorf("unable to copy '%s' to '%s': %w", sourcePath, hubDirScenarioPath, err)
}
// after
if err := os.MkdirAll(filepath.Dir(hubDirScenarioPath), os.ModePerm); err != nil {
	return err
}
if err := Copy(sourcePath, hubDirScenarioPath); err != nil {
	return fmt.Errorf("unable to copy '%s' to '%s': %w", sourcePath, hubDirScenarioPath, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(sourcePath); err != nil {
	return fmt.Errorf("hub scenario missing: %w", err)
}

Try / catch

if err := Copy(sourcePath, dest); err != nil {
	var perr *os.PathError
	if errors.As(err, &perr) && os.IsPermission(err) {
		return fmt.Errorf("fix permissions on %s: %w", filepath.Dir(dest), err)
	}
	return err
}

Prevention

When it happens

Trigger: installScenario -> installScenarioItem where Copy(sourcePath, hubDirScenarioPath) fails: the hub scenario file is absent, the destination directory doesn't exist/hasn't been created with correct permissions, or disk is full.

Common situations: Corrupted or partially updated hub (cscli hub update interrupted); read-only filesystem or container; the test runtime directory was pre-created by root and tests run as another user.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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