Skip to content

Commit 4381860

Browse files
authored
fix: Make state show command exit with code 1 if the stored state cannot be marshalled for rendering (#37933)
Prior to this change, when running a `state show` command with an address for a resource that existed in state but didn't match the current schema of the resource, users would see the "Failed to marshal" error but would also see output saying "The state file is empty. No resources are represented". This is misleading, as the state file isn't empty. Also, the command would exit with code 0 despite the error.
1 parent 1a54777 commit 4381860

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: BUG FIXES
2+
body: '`state show`: The `state show` command will now explicitly fail and return code 1 when it fails to render the named resources state'
3+
time: 2025-11-21T18:30:45.571448Z
4+
custom:
5+
Issue: "37933"

internal/command/state_show.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func (c *StateShowCommand) Run(args []string) int {
149149
root, outputs, err := jsonstate.MarshalForRenderer(statefile.New(singleInstance, "", 0), schemas)
150150
if err != nil {
151151
c.Streams.Eprintf("Failed to marshal state to json: %s", err)
152+
return 1
152153
}
153154

154155
jstate := jsonformat.State{

internal/command/state_show_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,69 @@ func TestStateShow(t *testing.T) {
7676
}
7777
}
7878

79+
func TestStateShow_errorMarshallingState(t *testing.T) {
80+
state := states.BuildState(func(s *states.SyncState) {
81+
s.SetResourceInstanceCurrent(
82+
addrs.Resource{
83+
Mode: addrs.ManagedResourceMode,
84+
Type: "test_instance",
85+
Name: "foo_invalid",
86+
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
87+
&states.ResourceInstanceObjectSrc{
88+
// The error is caused by the state containing attributes that don't
89+
// match the schema for the resource.
90+
AttrsJSON: []byte(`{"non_existent_attr":"I'm gonna cause an error!"}`),
91+
Status: states.ObjectReady,
92+
},
93+
addrs.AbsProviderConfig{
94+
Provider: addrs.NewDefaultProvider("test"),
95+
Module: addrs.RootModule,
96+
},
97+
)
98+
})
99+
statePath := testStateFile(t, state)
100+
101+
p := testProvider()
102+
p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
103+
ResourceTypes: map[string]providers.Schema{
104+
"test_instance": {
105+
Body: &configschema.Block{
106+
Attributes: map[string]*configschema.Attribute{
107+
"id": {Type: cty.String, Optional: true, Computed: true},
108+
"foo": {Type: cty.String, Optional: true},
109+
"bar": {Type: cty.String, Optional: true},
110+
},
111+
},
112+
},
113+
},
114+
}
115+
116+
streams, done := terminal.StreamsForTesting(t)
117+
c := &StateShowCommand{
118+
Meta: Meta{
119+
testingOverrides: metaOverridesForProvider(p),
120+
Streams: streams,
121+
},
122+
}
123+
124+
args := []string{
125+
"-state", statePath,
126+
"test_instance.foo_invalid",
127+
}
128+
code := c.Run(args)
129+
output := done(t)
130+
if code != 1 {
131+
t.Fatalf("unexpected code: %d\n\n%s", code, output.Stdout())
132+
}
133+
134+
// Test that error outputs were displayed
135+
expected := "unsupported attribute \"non_existent_attr\""
136+
actual := output.Stderr()
137+
if !strings.Contains(actual, expected) {
138+
t.Fatalf("Expected stderr output to include:\n%q\n\n Instead got:\n%q", expected, actual)
139+
}
140+
}
141+
79142
func TestStateShow_multi(t *testing.T) {
80143
submod, _ := addrs.ParseModuleInstanceStr("module.sub")
81144
state := states.BuildState(func(s *states.SyncState) {

0 commit comments

Comments
 (0)