derailed/k9s · error

data section in secret description is invalid

Error message

data section in secret description is invalid

What it means

Thrown by Secret.Decode after the '====' separator was found but the description ends immediately after it (dataEndIndex+4 >= len(encodedDescription)). That means the describe body is truncated exactly at the separator, leaving no text after the marker to keep as the decoded section's prefix. The parser treats this as a malformed data section and refuses to guess.

Source

Thrown at internal/dao/secret.go:99

	return buff.String(), nil
}

// SetDecodeData toggles decode mode.
func (s *Secret) SetDecodeData(b bool) {
	s.decodeData = b
}

// Decode removes the encoded part from the secret's description and appends the
// secret's decoded data.
func (s *Secret) Decode(encodedDescription, path string) (string, error) {
	dataEndIndex := strings.Index(encodedDescription, "====")
	if dataEndIndex == -1 {
		return "", fmt.Errorf("unable to find data section in secret description")
	}

	dataEndIndex += 4
	if dataEndIndex >= len(encodedDescription) {
		return "", fmt.Errorf("data section in secret description is invalid")
	}

	// Remove the encoded part from k8s's describe API
	// More details about the reasoning of index: https://github.com/kubernetes/kubectl/blob/v0.29.0/pkg/describe/describe.go#L2542
	body := encodedDescription[0:dataEndIndex]

	o, err := s.Get(context.Background(), path)
	if err != nil {
		return "", err
	}
	data, err := ExtractSecrets(o)
	if err != nil {
		return "", err
	}
	decodedSecrets := make([]string, 0, len(data))
	for _, k := range slices.Sorted(maps.Keys(data)) {
		line := fmt.Sprintf("%s: %s", k, data[k])
		decodedSecrets = append(decodedSecrets, strings.TrimSpace(line))

View on GitHub (pinned to 2d3ccc6ba2)

Solutions

  1. Confirm the Secret has data keys: kubectl get secret <name> -o jsonpath='{.data}' should not be empty
  2. Inspect kubectl describe secret <name> output and check content exists after the '====' line
  3. Re-run describe: a truncated response can be transient when the API server is under load
  4. Match k9s version to your cluster's kubectl describe format, or fall back to kubectl get secret -o yaml
Defensive patterns

Strategy: fallback

Validate before calling

dataEnd := strings.Index(desc, "====")
if dataEnd == -1 || dataEnd+4 >= len(desc) {
    return desc, nil // no usable data section; use raw description
}
decoded, err := s.Decode(desc, path)

Try / catch

if decoded, err := s.Decode(desc, path); err != nil {
    slog.Warn("secret decode failed; falling back", slogs.Error, err)
    return desc, nil
} else {
    return decoded, nil
}

Prevention

When it happens

Trigger: Decode() is called on describe output where '====' is the last four characters: an empty Data section rendered as only the marker line, a truncated describe response from the API server, or describe output generated by a tool that appends the separator without the following content.

Common situations: Empty Secrets (no .data keys) on clusters whose describer still prints the '====' trailer; piping partial describe output into the decoder; version skew between the kubectl describe format k9s expects and what the cluster emits.

Related errors


AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15). Data as JSON: /api/errors/87c78ca4caace069. Report an issue: GitHub.