github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/statefile/diagnostics.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package statefile
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  
    10  	"github.com/terramate-io/tf/tfdiags"
    11  )
    12  
    13  const invalidFormat = "Invalid state file format"
    14  
    15  // jsonUnmarshalDiags is a helper that translates errors returned from
    16  // json.Unmarshal into hopefully-more-helpful diagnostics messages.
    17  func jsonUnmarshalDiags(err error) tfdiags.Diagnostics {
    18  	var diags tfdiags.Diagnostics
    19  	if err == nil {
    20  		return diags
    21  	}
    22  
    23  	switch tErr := err.(type) {
    24  	case *json.SyntaxError:
    25  		// We've usually already successfully parsed a source file as JSON at
    26  		// least once before we'd use jsonUnmarshalDiags with it (to sniff
    27  		// the version number) so this particular error should not appear much
    28  		// in practice.
    29  		diags = diags.Append(tfdiags.Sourceless(
    30  			tfdiags.Error,
    31  			invalidFormat,
    32  			fmt.Sprintf("The state file could not be parsed as JSON: syntax error at byte offset %d.", tErr.Offset),
    33  		))
    34  	case *json.UnmarshalTypeError:
    35  		// This is likely to be the most common area, describing a
    36  		// non-conformance between the file and the expected file format
    37  		// at a semantic level.
    38  		if tErr.Field != "" {
    39  			diags = diags.Append(tfdiags.Sourceless(
    40  				tfdiags.Error,
    41  				invalidFormat,
    42  				fmt.Sprintf("The state file field %q has invalid value %s", tErr.Field, tErr.Value),
    43  			))
    44  			break
    45  		} else {
    46  			// Without a field name, we can't really say anything helpful.
    47  			diags = diags.Append(tfdiags.Sourceless(
    48  				tfdiags.Error,
    49  				invalidFormat,
    50  				"The state file does not conform to the expected JSON data structure.",
    51  			))
    52  		}
    53  	default:
    54  		// Fallback for all other types of errors. This can happen only for
    55  		// custom UnmarshalJSON implementations, so should be encountered
    56  		// only rarely.
    57  		diags = diags.Append(tfdiags.Sourceless(
    58  			tfdiags.Error,
    59  			invalidFormat,
    60  			fmt.Sprintf("The state file does not conform to the expected JSON data structure: %s.", err.Error()),
    61  		))
    62  	}
    63  
    64  	return diags
    65  }