github.com/opentofu/opentofu@v1.7.1/internal/states/statefile/diagnostics.go (about)

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