hasura/graphql-engine · error · errors.Error

marshal file: %w

Error message

marshal file: %w

What it means

rawGlobalConfig.write serializes the in-memory global config with json.MarshalIndent before saving; this error wraps a marshaling failure. Because the struct holds plain JSON-compatible values, it essentially only fires when a field contains data JSON cannot represent (NaN/Inf floats, cycles, or unsupported channel/func types after struct changes).

Source

Thrown at cli/global_config.go:100

	if c.ShowUpdateNotification == nil {
		trueVal := true
		c.ShowUpdateNotification = &trueVal
		c.shoudlWrite = true
	}

	if c.CLIEnvironment == "" {
		c.CLIEnvironment = DefaultEnvironment
	}

	return nil
}

func (c *rawGlobalConfig) write(filename string) error {
	var op errors.Op = "cli.rawGlobalConfig.write"

	b, err := json.MarshalIndent(c, "", "  ")
	if err != nil {
		return errors.E(op, fmt.Errorf("marshal file: %w", err))
	}

	err = os.WriteFile(filename, b, 0o644)
	if err != nil {
		return errors.E(op, fmt.Errorf("write file: %w", err))
	}

	return nil
}

// setupGlobConfig ensures that global config directory and file exists and
// reads it into the GlobalConfig object.
func (ec *ExecutionContext) setupGlobalConfig() error {
	var op errors.Op = "cli.ExecutionContext.setupGlobalConfig"
	// check if the directory name is set, else default
	if len(ec.GlobalConfigDir) == 0 {
		ec.Logger.Debug("global config directory is not pre-set, defaulting")

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Inspect and sanitize config values (replace NaN/Inf with valid numbers or omit the key) before saving
  2. Regenerate the global config from defaults (delete it and re-run init/setup)
  3. Pin/align tool versions between write and read paths if a schema change is suspected

Example fix

// before
raw.Timeout = math.NaN()   // json: unsupported value: NaN
// after
raw.Timeout = 30 * time.Second
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := json.MarshalIndent(rawCfg, "", "  "); err != nil {
    log.Fatalf("global config contains unserializable values: %v", err)
}

Type guard

func isMarshalable(v any) bool {
    _, err := json.Marshal(v)
    return err == nil
}

Try / catch

if err := setupGlobalConfig(); err != nil {
    var typeErr *json.UnsupportedTypeError
    if stderrors.As(err, &typeErr) {
        // a struct field holds an unmarshalable value; sanitize or drop it before retrying
    }
}

Prevention

When it happens

Trigger: setupGlobalConfig persisting a rawGlobalConfig containing a NaN or +Inf float (e.g. parsed from an exotic config source) or a struct layout with unmarshalable fields introduced by a version change.

Common situations: Version upgrade adding a field the old writer cannot marshal; programmatic manipulation of the config struct injecting NaN; extremely rare in normal CLI usage.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/0d6b6ca744a208e5. Report an issue: GitHub.