{"record":{"id":"8b0f6d9c30dcfdf2","repo":"nektos/act","slug":"invalid-security-opt-q","errorCode":null,"errorMessage":"invalid --security-opt: %q","messagePattern":"invalid --security-opt: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/container/docker_cli.go","lineNumber":944,"sourceCode":"\nfunc parseLoggingOpts(loggingDriver string, loggingOpts []string) (map[string]string, error) {\n\tloggingOptsMap := opts.ConvertKVStringsToMap(loggingOpts)\n\tif loggingDriver == \"none\" && len(loggingOpts) > 0 {\n\t\treturn map[string]string{}, fmt.Errorf(\"invalid logging opts for driver %s\", loggingDriver)\n\t}\n\treturn loggingOptsMap, nil\n}\n\n// takes a local seccomp daemon, reads the file contents for sending to the daemon\nfunc parseSecurityOpts(securityOpts []string) ([]string, error) {\n\tfor key, opt := range securityOpts {\n\t\tk, v, ok := strings.Cut(opt, \"=\")\n\t\tif !ok && k != \"no-new-privileges\" {\n\t\t\tk, v, ok = strings.Cut(opt, \":\")\n\t\t}\n\t\tif (!ok || v == \"\") && k != \"no-new-privileges\" {\n\t\t\t// \"no-new-privileges\" is the only option that does not require a value.\n\t\t\treturn securityOpts, fmt.Errorf(\"invalid --security-opt: %q\", opt)\n\t\t}\n\t\tif k == \"seccomp\" {\n\t\t\tswitch v {\n\t\t\tcase seccompProfileDefault, seccompProfileUnconfined:\n\t\t\t\t// known special names for built-in profiles, nothing to do.\n\t\t\tdefault:\n\t\t\t\t// value may be a filename, in which case we send the profile's\n\t\t\t\t// content if it's valid JSON.\n\t\t\t\tf, err := os.ReadFile(v)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn securityOpts, fmt.Errorf(\"opening seccomp profile (%s) failed: %w\", v, err)\n\t\t\t\t}\n\t\t\t\tvar b bytes.Buffer\n\t\t\t\tif err := json.Compact(&b, f); err != nil {\n\t\t\t\t\treturn securityOpts, fmt.Errorf(\"compacting json for seccomp profile (%s) failed: %w\", v, err)\n\t\t\t\t}\n\t\t\t\tsecurityOpts[key] = \"seccomp=\" + b.String()\n\t\t\t}","sourceCodeStart":926,"sourceCodeEnd":962,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/container/docker_cli.go#L926-L962","documentation":"parseSecurityOpts accepts --security-opt entries in key=value or key:value form, with the single exception of the valueless 'no-new-privileges'. Any other entry without a value ('seccomp', 'apparmor' alone) or with an empty value ('apparmor=') fails with this error before the container starts.","triggerScenarios":"Passing --security-opt seccomp (no value), --security-opt apparmor: (empty value), or a misspelled 'no-new-priviledges' (typo, so the exemption does not apply) in job/container options.","commonSituations":"Typos in the valueless option name; assuming all security opts are valueless; YAML stripping empty-string values to bare keys; copying examples that used shell-quoting that got mangled.","solutions":["Give the option a value: --security-opt seccomp=unconfined or --security-opt apparmor=docker-default","Spell the valueless option exactly: --security-opt no-new-privileges","Check YAML for keys whose value was dropped (key: with nothing after)"],"exampleFix":"# before\noptions: --security-opt seccomp\n\n# after\noptions: --security-opt seccomp=unconfined","handlingStrategy":"validation","validationCode":"for _, opt := range securityOpts {\n    k, v, hasEq := strings.Cut(opt, \"=\")\n    if !hasEq { _, v, _ = strings.Cut(opt, \":\") }\n    if v == \"\" && k != \"no-new-privileges\" {\n        return fmt.Errorf(\"security-opt %q needs a value\", opt)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only 'no-new-privileges' is valueless — everything else needs key=value or key:value","Spell option names exactly; typos lose the exemption","Watch YAML that drops empty values"],"tags":["docker","security","seccomp","validation","act"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}