crowdsecurity/crowdsec · error

unable to write blank acquis file '%s': %w

Error message

unable to write blank acquis file '%s': %w

What it means

This error is returned by HubTestItem.Run for non-appsec tests when writing the blank acquisition file (os.WriteFile of an empty string to t.RuntimeAcquisFilePath) fails. Crowdsec still needs an acquis file to start, so tests without appsec rules get an empty one; the write failure wraps the OS error.

Source

Thrown at pkg/hubtest/hubtest_item.go:658

	}

	// if it's an appsec rule test, we need acquis and appsec profile
	if len(t.Config.AppsecRules) > 0 {
		// copy template acquis file to runtime folder
		log.Debugf("copying %s to %s", t.TemplateAcquisPath, t.RuntimeAcquisFilePath)

		if err = Copy(t.TemplateAcquisPath, t.RuntimeAcquisFilePath); err != nil {
			return fmt.Errorf("unable to copy '%s' to '%s': %w", t.TemplateAcquisPath, t.RuntimeAcquisFilePath, err)
		}

		log.Debugf("copying %s to %s", t.TemplateAppsecProfilePath, filepath.Join(t.RuntimePath, "appsec-configs", "config.yaml"))
		// copy template appsec-config file to runtime folder
		if err = Copy(t.TemplateAppsecProfilePath, filepath.Join(t.RuntimePath, "appsec-configs", "config.yaml")); err != nil {
			return fmt.Errorf("unable to copy '%s' to '%s': %w", t.TemplateAppsecProfilePath, filepath.Join(t.RuntimePath, "appsec-configs", "config.yaml"), err)
		}
	} else { // otherwise we drop a blank acquis file
		if err = os.WriteFile(t.RuntimeAcquisFilePath, []byte(""), os.ModePerm); err != nil {
			return fmt.Errorf("unable to write blank acquis file '%s': %w", t.RuntimeAcquisFilePath, err)
		}
	}

	// install the hub in the runtime folder
	if err = t.InstallHub(ctx); err != nil {
		return fmt.Errorf("unable to install hub in '%s': %w", t.RuntimeHubPath, err)
	}

	if t.Config.LogFile != "" {
		return t.RunWithLogFile(ctx)
	}

	if t.Config.NucleiTemplate != "" {
		return t.RunWithNucleiTemplate(ctx)
	}

	return fmt.Errorf("log file or nuclei template must be set in '%s'", t.Name)
}

View on GitHub (pinned to 909b515798)

Solutions

  1. Check the wrapped error: for permission issues, fix ownership/permissions on the runtime directory.
  2. Ensure no concurrent test runs share the same t.RuntimePath; isolate runtime folders per test.
  3. Remove stale runtime folders and re-run.
  4. Check that t.RuntimeAcquisFilePath is not an existing directory and disk space is available.

Example fix

// before
item.Run(ctx, patternDir) // "unable to write blank acquis file ...: permission denied"
// after: ensure writable runtime before running
if err := os.Chmod(item.RuntimePath, 0o755); err != nil { ... }
if err := item.Run(ctx, patternDir); err != nil { ... }
Defensive patterns

Strategy: validation

Validate before calling

if err := os.MkdirAll(filepath.Dir(item.RuntimeAcquisFilePath), 0o755); err != nil {
    return fmt.Errorf("acquis dir not writable: %w", err)
}
if fi, err := os.Stat(item.RuntimeAcquisFilePath); err == nil && fi.IsDir() {
    return fmt.Errorf("%s is a directory", item.RuntimeAcquisFilePath)
}

Try / catch

if err := item.Run(ctx, patternDir); err != nil {
    if os.IsPermission(errors.Unwrap(err)) {
        return fmt.Errorf("fix permissions on %s: %w", item.RuntimePath, err)
    }
    return err
}

Prevention

When it happens

Trigger: HubTestItem.Run with no AppsecRules configured, and the runtime acquis path is unwritable, its parent directory was removed mid-run, or the destination exists as a directory.

Common situations: Runtime folder deleted between createDirs and the write (concurrent test runs sharing a runtime path); permission changes mid-run; read-only mount or full disk during CI.

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