hashicorp/terraform · error

Key could not be found

Error message

Key %q could not be found

What it means

In RemoteClient.Get, when the state is stored in chunked mode, the manifest at the state path lists per-chunk KV paths. The client fetches each chunk; if any chunk returns a nil pair (key deleted or never written), this fires. It means the chunk index disagrees with Consul's KV store — the state is partially missing.

Solutions

  1. Inspect the manifest at the state key: `consul kv get <state-path>` and note the chunks array and current-hash.
  2. For each chunk path in the list, check `consul kv get <chunk>` to identify which are missing.
  3. Restore the missing chunks or the whole state prefix from a Consul snapshot taken when the state was consistent.
  4. If unrecoverable, restore a known-good state file and re-run terraform apply to reconcile.
Defensive patterns

Strategy: validation

Validate before calling

// Before relying on Get(), verify the chunk manifest agrees with KV.
func verifyChunksPresent(client *consulapi.Client, statePath string) error {
    pair, _, err := client.KV().Get(statePath, nil)
    if err != nil {
        return err
    }
    if pair == nil {
        return nil // not chunked or absent
    }
    var manifest struct {
        CurrentHash string   `json:"current-hash"`
        Chunks      []string `json:"chunks"`
    }
    if err := json.Unmarshal(pair.Value, &manifest); err != nil || manifest.CurrentHash == "" {
        return nil // single-entry mode
    }
    for _, c := range manifest.Chunks {
        p, _, err := client.KV().Get(c, nil)
        if err != nil {
            return fmt.Errorf("checking chunk %s: %w", c, err)
        }
        if p == nil {
            return fmt.Errorf("missing chunk %s; state is corrupt", c)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: RemoteClient.Get -> chunkedMode() returns chunked=true and a list of chunk paths; for one of them kv.Get(c) returns (nil, nil).

Common situations: Manual deletion of chunk keys under tfstate.<hash>/; a previous Put crashed between writing chunks and the manifest; another writer concurrently rewrote and trimmed chunks; Consul lost data after a bad snapshot restore.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/4ec94156b8102bbc. Report an issue: GitHub.

Appendix: source

Thrown at internal/backend/remote-state/consul/client.go:101

	chunked, hash, chunks, pair, err := c.chunkedMode()
	if err != nil {
		return nil, diags.Append(err)
	}
	if pair == nil {
		return nil, diags
	}

	c.modifyIndex = pair.ModifyIndex

	var payload []byte
	if chunked {
		for _, c := range chunks {
			pair, _, err := kv.Get(c, nil)
			if err != nil {
				return nil, diags.Append(err)
			}
			if pair == nil {
				return nil, diags.Append(fmt.Errorf("Key %q could not be found", c))
			}
			payload = append(payload, pair.Value[:]...)
		}
	} else {
		payload = pair.Value
	}

	// If the payload starts with 0x1f, it's gzip, not json
	if len(payload) >= 1 && payload[0] == '\x1f' {
		payload, err = uncompressState(payload)
		if err != nil {
			return nil, diags.Append(err)
		}
	}

	md5 := md5.Sum(payload)

	if hash != "" && fmt.Sprintf("%x", md5) != hash {

View on GitHub (pinned to d32a084675)