nektos/act · error

compacting json for seccomp profile (%s) failed: %w

Error message

compacting json for seccomp profile (%s) failed: %w

What it means

Thrown while converting a seccomp profile security option for a container. act supports the special values 'unconfined' and 'default'; any other value is treated as a path to a file containing the seccomp profile JSON, which is read and compacted with json.Compact before being passed to Docker. This error means the file was read successfully but its content is not valid JSON, so json.Compact failed.

Source

Thrown at pkg/container/docker_cli.go:959

		}
		if (!ok || v == "") && k != "no-new-privileges" {
			// "no-new-privileges" is the only option that does not require a value.
			return securityOpts, fmt.Errorf("invalid --security-opt: %q", opt)
		}
		if k == "seccomp" {
			switch v {
			case seccompProfileDefault, seccompProfileUnconfined:
				// known special names for built-in profiles, nothing to do.
			default:
				// value may be a filename, in which case we send the profile's
				// content if it's valid JSON.
				f, err := os.ReadFile(v)
				if err != nil {
					return securityOpts, fmt.Errorf("opening seccomp profile (%s) failed: %w", v, err)
				}
				var b bytes.Buffer
				if err := json.Compact(&b, f); err != nil {
					return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %w", v, err)
				}
				securityOpts[key] = "seccomp=" + b.String()
			}
		}
	}

	return securityOpts, nil
}

// parseSystemPaths checks if `systempaths=unconfined` security option is set,
// and returns the `MaskedPaths` and `ReadonlyPaths` accordingly. An updated
// list of security options is returned with this option removed, because the
// `unconfined` option is handled client-side, and should not be sent to the
// daemon.
func parseSystemPaths(securityOpts []string) (filtered, maskedPaths, readonlyPaths []string) {
	filtered = securityOpts[:0]
	for _, opt := range securityOpts {
		if opt == "systempaths=unconfined" {

View on GitHub (pinned to 4f41128141)

Solutions

  1. Validate the profile file with a JSON parser: jq . /path/to/profile.json or python -m json.tool
  2. Re-download or regenerate the seccomp profile from a trusted source (e.g. moby/default-seccomp.json)
  3. Use the built-in values --security-opt seccomp=unconfined or seccomp=default if a custom profile is not required
  4. Ensure the path is to a regular file containing the raw JSON profile, not YAML or a wrapper script

Example fix

# before
--security-opt seccomp=./my-profile.yaml

# after
--security-opt seccomp=./my-profile.json  # jq . my-profile.json must succeed
Defensive patterns

Strategy: validation

Validate before calling

# shell, before running act
f=$(printf '%s' "$opts" | grep -oP '(?<=seccomp=)\S+' || true)
[ -n "$f" ] && [ "${f##*/}" != "unconfined" ] && [ "${f##*/}" != "default" ] && jq empty "$f"

Prevention

When it happens

Trigger: Setting the container option --security-opt seccomp=<path> where <path> is neither 'default' nor 'unconfined', and the referenced file exists but contains malformed JSON (truncated profile, YAML instead of JSON, HTML error page, BOM, or comments).

Common situations: User points seccomp at a Docker/OCI profile downloaded partially, edited by hand, saved as YAML, or references a file with a UTF-8 BOM. Also happens when the path accidentally resolves to a directory or non-profile file that is still readable.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/92233a5b9ea7bce3. Report an issue: GitHub.