matryer/xbar · error
json.MarshalIndent
Error message
json.MarshalIndent
What it means
SaveVariableValues serializes the plugin's variable values with json.MarshalIndent before writing <pluginPath>.vars.json. This error wraps any Marshal failure. Because values are map[string]interface{}, marshaling fails only when a value contains an unsupported type (e.g. a channel, func, complex number, or a struct with unexported/invalid fields) or an invalid UTF-8/radical type that json cannot represent.
Source
Thrown at pkg/plugins/variables.go:23
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"sync"
"github.com/matryer/xbar/pkg/metadata"
"github.com/pkg/errors"
)
// variableJSONFileExt is the extension for the variable JSON payload.
const variableJSONFileExt = ".vars.json"
// SaveVariableValues saves the values for a plugin.
func SaveVariableValues(pluginDir, installedPluginPath string, values map[string]interface{}) error {
b, err := json.MarshalIndent(values, "", "\t")
if err != nil {
return errors.Wrap(err, "json.MarshalIndent")
}
filename := filepath.Join(pluginDir, installedPluginPath+variableJSONFileExt)
err = ioutil.WriteFile(filename, b, 0666)
if err != nil {
return errors.Wrap(err, "WriteFile")
}
return nil
}
// LoadVariableValues loads the variables for a plugin.
func LoadVariableValues(pluginDir, installedPluginPath string) (map[string]interface{}, error) {
filename := filepath.Join(pluginDir, installedPluginPath+variableJSONFileExt)
f, err := os.Open(filename)
if err != nil {
if os.IsNotExist(err) {
// no file - but not an error, just empty map
return map[string]interface{}{}, nil
}View on GitHub (pinned to d624239058)
Solutions
- Sanitize values to plain JSON types (string, float64, bool, nil, []interface{}, map[string]interface{}) before calling SaveVariableValues
- Check errors.Cause(err) — it names the offending type, e.g. 'json: unsupported type: func()'; find and remove/convert that field
- Implement json.Marshaler on custom types you must persist, or convert to a serializable DTO first
Example fix
// before
values := map[string]interface{}{"callback": func() {}}
err := plugins.SaveVariableValues(dir, path, values) // json.MarshalIndent error
// after
values := map[string]interface{}{"name": cfg.Name, "timeout": cfg.Timeout.Seconds()}
if err := plugins.SaveVariableValues(dir, path, values); err != nil {
return fmt.Errorf("save variable values: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
func jsonSafe(v interface{}) error {
var b []byte
var err error
if b, err = json.Marshal(v); err != nil {
return err
}
_ = b
return nil
}
// call: if err := jsonSafe(values); err != nil { /* sanitize values */ } Try / catch
if err := plugins.SaveVariableValues(dir, path, values); err != nil {
var ute *json.UnsupportedTypeError
var uve *json.UnsupportedValueError
if errors.As(errors.Cause(err), &ute) {
log.Printf("cannot serialize type %v", ute.Type)
} else if errors.As(errors.Cause(err), &uve) {
log.Printf("cannot serialize value %v", uve.Value)
}
return err
} Prevention
- Store only plain JSON-shaped data (strings, numbers, bools, slices, maps) in variable values
- Implement json.Marshaler on custom types or convert to DTOs before saving
- Never put funcs, channels, or file handles in the values map
- Dry-run with json.Marshal to catch bad values before they hit the persistence path
When it happens
Trigger: Calling plugins.SaveVariableValues(pluginDir, installedPluginPath, values) where values contains a non-JSON-serializable value, such as a func, chan, os.File, sync.Mutex embedded in a struct being marshaled, or math.NaN/Inf floats (which produce an error in Go's json on unsupported types; NaN/Inf actually error via 'unsupported value').
Common situations: Passing raw Go structures holding handles (DB connections, file objects) instead of plain data; storing time.T without proper handling in older patterns; values captured from reflection-based code; nested maps containing custom types without MarshalJSON.
Related errors
AI-assisted analysis of matryer/xbar@d624239058 (2026-09-02).
Data as JSON: /api/errors/9704ce900ceb0d32.
Report an issue: GitHub.