puppetlabs/puppet · error · Puppet::Error
Invalid context to parse: %{context}
Error message
Invalid context to parse: %{context} What it means
Puppet::Util::SELinuxUtil-class method parse_selinux_context (selinux.rb:94) splits an SELinux context into seluser/selrole/seltype/selrange using the regex /^([^\s:]+):([^\s:]+):([^\s:]+)(?::([\sa-zA-Z0-9:,._-]+))?$/ on a single line. nil and the literal string 'unlabeled' short-circuit to nil (line 91); anything else that lacks at least three non-empty, colon-separated, whitespace-free fields raises Puppet::Error 'Invalid context to parse: <context>'.
Source
Thrown at lib/puppet/util/selinux.rb:94
# If the file exists we should pass the mode to selabel_lookup for the most specific
# matching. If not, we can pass a mode of 0.
mode = file_mode(file, resource_ensure)
retval = Selinux.selabel_lookup(handle, file, mode)
retval == -1 ? nil : retval[1]
end
# Take the full SELinux context returned from the tools and parse it
# out to the three (or four) component parts. Supports :seluser, :selrole,
# :seltype, and on systems with range support, :selrange.
def parse_selinux_context(component, context)
if context.nil? or context == "unlabeled"
return nil
end
components = /^([^\s:]+):([^\s:]+):([^\s:]+)(?::([\sa-zA-Z0-9:,._-]+))?$/.match(context)
unless components
raise Puppet::Error, _("Invalid context to parse: %{context}") % { context: context }
end
case component
when :seluser
components[1]
when :selrole
components[2]
when :seltype
components[3]
when :selrange
components[4]
else
raise Puppet::Error, _("Invalid SELinux parameter type")
end
end
# This updates the actual SELinux label on the file. You can update
# only a single component or update the entire context.View on GitHub (pinned to e227c27540)
Solutions
- Handle the documented empty cases yourself first: return early when context.nil? || context == 'unlabeled'.
- Take only the context field from tool output (e.g., split and select the token matching user:role:type) rather than the whole line.
- Pre-validate with the same regex the library uses: ctx =~ /^([^\s:]+):([^\s:]+):([^\s:]+)(?::([\sa-zA-Z0-9:,._-]+))?$/ before calling.
- Rescue Puppet::Error around parse calls and log the raw string to identify which tool produced the malformed context.
Example fix
// before
range = parse_selinux_context(:selrange, raw_ls_z_output) # whole line 'unconfined_u:object_r:user_home_t:s0 file.txt'
// after
line = raw.to_s.lines.first.to_s
ctx = line.split.find { |t| t.count(':') >= 2 && t =~ /\A[^\s:]+:[^\s:]+:[^\s:]+/ }
range = ctx.nil? ? nil : parse_selinux_context(:selrange, ctx) Defensive patterns
Strategy: validation
Validate before calling
CTX_RX = /\A([^\s:]+):([^\s:]+):([^\s:]+)(?::([\sa-zA-Z0-9:,._-]+))?\z/ def selinux_context_str?(ctx) !ctx.nil? && ctx != 'unlabeled' && ctx.match?(CTX_RX) end
Try / catch
begin
parse_selinux_context(component, ctx)
rescue Puppet::Error => e
Puppet.debug("unparseable selinux context #{ctx.inspect}: #{e.message}")
nil
end Prevention
- Early-return on nil and 'unlabeled' before calling the parser.
- Extract just the context token (>=2 colons) from ls -Z / matchpathcon output.
When it happens
Trigger: parse_selinux_context(:selrange, 'unconfined_u:unconfined_r') (only two fields); a context with embedded spaces 'system_u : system_r'; a lone placeholder like '?' or '-' returned by tools; a multiline string passed as the context. Note the pattern is per-line: use the first line of `ls -Z`/lgetfilecon output only.
Common situations: File resources on filesystems without SELinux labeling that return odd sentinel strings instead of 'unlabeled'; parsing `ls -Z` or `matchpathcon` output where columns are blank; custom ranges containing unexpected characters not in [a-zA-Z0-9:,._ -].
Related errors
- Unable to parse '#{simple}' as a version range identifier
- Could not open SELinux category translation file %{path}.
- One or more file(s) specified did not exist: %{files}
- a data type must have an interface
- Resource instance does not match request key
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/6105c6d3bf7ad752.
Report an issue: GitHub.