hasura/graphql-engine · error · errors.Error

write global config file: %w

Error message

write global config file: %w

What it means

During first-run initialization, gc.write(ec.GlobalConfigFile) failed after the empty config object was successfully created and validated. It is a plain disk I/O failure writing the marshaled YAML/JSON — the same class as error 210, but occurring on the create-new-file path rather than the rewrite path.

Source

Thrown at cli/global_config.go:161

	if stderrors.Is(err, fs.ErrNotExist) {
		// file does not exist, teat as first run and create it
		ec.Logger.Debug(
			"global config file does not exist, this could be the first run, creating it...",
		)

		// create an empty config object
		gc := &rawGlobalConfig{}

		// populate the keys
		err := gc.validateKeys()
		if err != nil {
			return errors.E(op, fmt.Errorf("setup global config object: %w", err))
		}

		// write the file
		err = gc.write(ec.GlobalConfigFile)
		if err != nil {
			return errors.E(op, fmt.Errorf("write global config file: %w", err))
		}

		ec.Logger.Debugf(
			"global config file written at '%s' with content '%v'",
			ec.GlobalConfigFile,
			gc,
		)

		// also show a notice about telemetry
		ec.Logger.Info(TelemetryNotice)
	} else if stderrors.Is(err, fs.ErrExist) || err == nil {
		// file exists, verify contents
		ec.Logger.Debug("global config file exists, verifying contents")

		// initialize the config object
		gc := rawGlobalConfig{}

		err := gc.read(ec.GlobalConfigFile)

View on GitHub (pinned to 724551b9ae)

Solutions

  1. chmod/chown the config directory so the invoking user can create files in it
  2. Pre-create the config file manually with valid content so initialization skips writing
  3. Move GlobalConfigDir to a writable path
  4. On Windows, check AV/EDR is not locking the config path

Example fix

# before
$ mycli setup  # fails on first run
# after
$ sudo chown -R $(id -u):$(id -g) ~/.mycli
$ mycli setup
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(ec.GlobalConfigFile); errors.Is(err, os.ErrNotExist) {
    if err := os.WriteFile(ec.GlobalConfigFile, []byte("uuid: \"\"\ncli_environment: \"\"\n"), 0o644); err != nil {
        return fmt.Errorf("cannot pre-seed config file: %w", err)
    }
}

Type guard

func canCreateFileIn(dir string) bool {
    f, err := os.CreateTemp(dir, ".probe")
    if err != nil {
        return false
    }
    _ = f.Close()
    _ = os.Remove(f.Name())
    return true
}

Try / catch

if err := ec.Prepare(ctx); err != nil {
    if strings.Contains(err.Error(), "write global config file") && ec.GlobalConfigFile != "" {
        ec.GlobalConfigFile = filepath.Join(os.TempDir(), GlobalConfigFileName)
        return ec.Prepare(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: Fresh install where the config file does not yet exist and the directory exists but is not writable (MkdirAll with os.ModePerm can succeed on a dir that is still not writable for the invoking user, e.g. sticky-bit or umask interactions), or a read-only filesystem.

Common situations: First run in a container, first run as a user without write access to the config dir created by an installer (root-owned ~/.<app>), or antivirus/mandatory locking on Windows blocking file creation.

Related errors


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