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