containerd/containerd · error
failed to marshal TOML blob for runtime %q: %w
Error message
failed to marshal TOML blob for runtime %q: %w
What it means
When decoding runtime options, the config marshals the raw TOML options table (r.Options) back to bytes with toml.Marshal, keyed by r.Type in the error message. If marshaling the in-memory options blob fails, this wrapped error is returned. This happens before unmarshaling into the concrete runtime-options type, so it indicates the stored options structure itself could not be re-encoded as TOML.
Source
Thrown at internal/cri/config/config.go:792
namespaceOptions := securityContext.GetNamespaceOptions()
if namespaceOptions.GetNetwork() == runtime.NamespaceMode_NODE ||
namespaceOptions.GetPid() == runtime.NamespaceMode_NODE ||
namespaceOptions.GetIpc() == runtime.NamespaceMode_NODE {
return true
}
return false
}
// GenerateRuntimeOptions generates runtime options from cri plugin config.
func GenerateRuntimeOptions(r Runtime) (any, error) {
if r.Options == nil {
return nil, nil
}
b, err := toml.Marshal(r.Options)
if err != nil {
return nil, fmt.Errorf("failed to marshal TOML blob for runtime %q: %w", r.Type, err)
}
options := getRuntimeOptionsType(r.Type)
if err := toml.Unmarshal(b, options); err != nil {
return nil, err
}
// For generic configuration, if no config path specified (preserving old behavior), pass
// the whole TOML configuration section to the runtime.
if runtimeOpts, ok := options.(*runtimeoptions.Options); ok && runtimeOpts.ConfigPath == "" {
runtimeOpts.ConfigBody = b
}
return options, nil
}
// getRuntimeOptionsType gets empty runtime options by the runtime type name.
func getRuntimeOptionsType(t string) any {View on GitHub (pinned to 4246446a2b)
Solutions
- Inspect and simplify the options table for the runtime named in the error in config.toml; use only scalar/string/bool/nested-table values.
- Regenerate the runtime options using the documented schema for the runtime_type (e.g. SystemdCgroup for runc).
- Upgrade/align containerd and the runtime so option marshaling matches expected types.
- If constructing Config in Go, ensure Options is a map[string]interface{} of TOML-encodable values.
Example fix
// before (config.toml) [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = "true" # odd type from template // after (config.toml) [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true
Defensive patterns
Strategy: validation
Validate before calling
_, err := toml.Marshal(runtime.Options)
if err != nil {
return fmt.Errorf("runtime %q options not TOML-encodable: %w", runtime.Type, err)
} Type guard
func tomlEncodable(v map[string]interface{}) bool {
_, err := toml.Marshal(v)
return err == nil
} Try / catch
b, err := toml.Marshal(r.Options)
if err != nil {
return nil, fmt.Errorf("runtime %q: %w", r.Type, err)
} Prevention
- Keep runtime options limited to documented scalar fields (booleans, strings, ints).
- Test config.toml parsing/marshaling in CI with the same containerd version as production.
- Avoid hand-rolled Config construction with arbitrary interface{} option values.
When it happens
Trigger: Call getRuntimeOptionsBlock for a runtime whose Options map contains values that the TOML marshaller cannot encode (unsupported nested types produced via config decoding or TOML edge cases), during containerd startup when loading runtime configs.
Common situations: Unusual/exotic values in the `[containerd.runtimes.X.options]` table of config.toml, plugin version changes altering how options are represented, or programmatically-built Config objects with non-encodable option values.
Related errors
- invalid cri image config: %w
- `mirrors` cannot be set when `config_path` is provided
- `default_runtime_name` is empty
- `cni.bin_dir` and `cni.bin_dirs` cannot be set at the same t
- `privileged_without_host_devices_all_devices_allowed` requir
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/0b3b4a277d9af28d.
Report an issue: GitHub.