hashicorp/terraform · error

cannot serialize updated credentials file

Error message

cannot serialize updated credentials file: %s

What it means

Thrown when json.MarshalIndent fails to serialize the in-memory credentials map (already updated with the new host entry) back to bytes. Because the source data was itself just decoded from JSON, a marshal failure here is extremely rare — it indicates an internal inconsistency such as a ctyjson.SimpleJSONValue whose nested Value cannot round-trip, or a value type marshal does not accept.

Solutions

  1. If you are embedding Terraform programmatically, verify the HostCredentialsWritable.ToStore() implementation returns a JSON-friendly cty.Value (string/number/object).
  2. For CLI users: back up and delete the credentials file, then re-run `terraform login` to rebuild a clean map.
  3. Capture the underlying error string (%s) to identify which value type marshal rejected.
  4. Check the Terraform version — a cty serialization regression could be the cause.
Defensive patterns

Strategy: try-catch

Try / catch

// When programmatically providing HostCredentialsWritable, ensure ToStore()
// returns a JSON-encodable cty.Value (string/number/bool/object of those).
func safeToStore(w svcauth.HostCredentialsWritable) error {
    v := w.ToStore()
    if _, err := ctyjson.Marshal(v, v.Type()); err != nil {
        return fmt.Errorf("ToStore value not JSON-encodable: %w", err)
    }
    return nil
}

Prevention

When it happens

Trigger: new.ToStore() produced a cty.Value that ctyjson cannot encode (e.g. contains types or marks unsupported by JSON); a nil/invalid value slipped into rawCredsMap via a programmatic caller; an exotic pre-existing entry that survived decode but cannot re-encode.

Common situations: Almost never seen in normal CLI use. Surfaces in programmatic embedding of Terraform where a custom HostCredentialsWritable.ToStore returns a non-JSON-encodable cty.Value, or when a corrupted in-memory map is passed.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/e4bd719f6e747716. Report an issue: GitHub.

Appendix: source

Thrown at internal/command/cliconfig/credentials.go:386

			delete(rawCredsMap, givenHost)
		}
	}

	// If we have a new object to store we'll write it in now. If the previous
	// object had the hostname written in a different way then this will
	// appear to change it into our canonical display form, with all the
	// letters in lowercase and other transforms from the Internationalized
	// Domain Names specification.
	if new != nil {
		toStore := new.ToStore()
		rawCredsMap[host.ForDisplay()] = ctyjson.SimpleJSONValue{
			Value: toStore,
		}
	}

	newSrc, err := json.MarshalIndent(raw, "", "  ")
	if err != nil {
		return fmt.Errorf("cannot serialize updated credentials file: %s", err)
	}

	// Now we'll write our new content over the top of the existing file.
	// Because we updated the data structure surgically here we should not
	// have disturbed the meaning of any other content in the file, but it
	// might have a different JSON layout than before.
	// We'll create a new file with a different name first and then rename
	// it over the old file in order to make the change as atomically as
	// the underlying OS/filesystem will allow.
	{
		dir, file := filepath.Split(filename)
		f, err := ioutil.TempFile(dir, file)
		if err != nil {
			return fmt.Errorf("cannot create temporary file to update credentials: %s", err)
		}
		tmpName := f.Name()
		moved := false
		defer func(f *os.File, name string) {

View on GitHub (pinned to d32a084675)