docker/cli · error

compacting json for seccomp profile

Error message

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

What it means

Thrown by parseSecurityOpts after successfully reading a seccomp profile file when json.Compact fails, meaning the file content is not valid JSON. The CLI compacts the JSON before embedding it inline in the security option sent to the daemon.

Solutions

  1. Validate the JSON with a parser: jq . /path/to/profile.json
  2. Start from the default profile (docker default seccomp profile) and modify incrementally
  3. Remove JSON comments (not valid in strict JSON) and trailing commas
  4. Re-save the file as UTF-8 without BOM

Example fix

# before (profile.json contains a comment)
{
  // seccomp rules
  "defaultAction": "SCMP_ACT_ERRNO"
}
# after
{
  "defaultAction": "SCMP_ACT_ERRNO"
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate JSON content of a seccomp profile before passing it to docker.
func validSeccompJSON(path string) error {
    b, err := os.ReadFile(path)
    if err != nil {
        return err
    }
    var v any
    return json.Unmarshal(b, &v)
}

if err := validSeccompJSON(profile); err != nil {
    return fmt.Errorf("seccomp profile not valid JSON: %w", err)
}

Prevention

When it happens

Trigger: Calling `docker run --security-opt seccomp=/path/to/profile.json` where the file is readable but contains syntax errors (trailing commas, comments, unquoted keys, truncated content, or non-JSON like YAML/INI).

Common situations: Hand-editing the profile and leaving a syntax error; saving the file in a different format; CRLF/encoding issues; copying a profile snippet that was incomplete; profile generated by a tool that emits YAML.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/3d2e993b99d510f5. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/container/opts.go:952

		}
		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 4f84911bfe)