opentofu/opentofu · critical

ephemeral resources are not meant to be stored in the state

Error message

ephemeral resources are not meant to be stored in the state file but schema for ephemeral %s.%s has been requested

What it means

jsonformat.State.GetSchema panics when asked for a schema for an ephemeral-mode resource: ephemeral resources must never persist into state files, so their presence indicates a malformed or foreign state file (or an internal bug). This is a panic, not a returned error.

Source

Thrown at internal/command/jsonformat/state.go:41

	RootModule         jsonstate.Module            `json:"root"`
	RootModuleOutputs  map[string]jsonstate.Output `json:"root_module_outputs"`

	ProviderFormatVersion string                            `json:"provider_format_version"`
	ProviderSchemas       map[string]*jsonprovider.Provider `json:"provider_schemas"`
}

func (state State) Empty() bool {
	return len(state.RootModuleOutputs) == 0 && len(state.RootModule.Resources) == 0 && len(state.RootModule.ChildModules) == 0
}

func (state State) GetSchema(resource jsonstate.Resource) *jsonprovider.Schema {
	switch resource.Mode {
	case jsonstate.ManagedResourceMode:
		return state.ProviderSchemas[resource.ProviderName].ResourceSchemas[resource.Type]
	case jsonstate.DataResourceMode:
		return state.ProviderSchemas[resource.ProviderName].DataSourceSchemas[resource.Type]
	case jsonstate.EphemeralResourceMode:
		panic(fmt.Errorf("ephemeral resources are not meant to be stored in the state file but schema for ephemeral %s.%s has been requested", resource.Type, resource.Name))
	default:
		panic("found unrecognized resource mode: " + resource.Mode)
	}
}

func (state State) renderHumanStateModule(renderer Renderer, module jsonstate.Module, opts computed.RenderHumanOpts, first bool) {
	if len(module.Resources) > 0 && !first {
		renderer.Streams.Println()
	}

	for _, resource := range module.Resources {

		if !first {
			renderer.Streams.Println()
		}

		if first {
			first = false

View on GitHub (pinned to 3561785c48)

Solutions

  1. Reproduce the state with the current OpenTofu binary (fresh apply or refresh) instead of reusing the foreign state file
  2. Do not hand-edit state files; use 'tofu state' commands only
  3. If 'tofu show -json' on a freshly written state panics, report a bug including the state redacted
Defensive patterns

Strategy: validation

Validate before calling

func containsEphemeralResources(m jsonstate.Module) bool {
    for _, r := range m.Resources {
        if r.Mode == jsonstate.EphemeralResourceMode {
            return true
        }
    }
    for _, c := range m.ChildModules {
        if containsEphemeralResources(c) {
            return true
        }
    }
    return false
}

Type guard

func isRenderableStateMode(m jsonstate.ResourceMode) bool {
    return m == jsonstate.ManagedResourceMode || m == jsonstate.DataResourceMode
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        err = fmt.Errorf("state renderer panic (likely foreign state file): %v", r)
    }
}()

Prevention

When it happens

Trigger: Rendering a state file whose resources array contains an entry with mode "ephemeral" - state written by a different OpenTofu version, hand-crafted state JSON, or corruption.

Common situations: State files migrated or restored across versions, external tooling that generates state JSON, testing fixtures with wrong mode strings.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/1c1a38aa519405ac. Report an issue: GitHub.