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
- If you are embedding Terraform programmatically, verify the HostCredentialsWritable.ToStore() implementation returns a JSON-friendly cty.Value (string/number/object).
- For CLI users: back up and delete the credentials file, then re-run `terraform login` to rebuild a clean map.
- Capture the underlying error string (%s) to identify which value type marshal rejected.
- 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
- Keep ToStore() outputs to primitive cty types.
- Round-trip test credentials write/read in unit tests.
- Upgrade cty/terraform together to avoid serialization regressions.
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
- Can't serialize backend configuration as JSON
- could not interpret output
- could not marshal output
- credentials file has invalid value for "credentials"…
- error converting output values to json
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)