cilium/cilium · error

failed to unmarshal bgp routes from %s: %w

Error message

failed to unmarshal bgp routes from %s: %w

What it means

After a successful exec of `cilium bgp routes ... -o json` in the agent pod, fetchRoutesFromPod (cilium-cli/bgp/routes.go:130) unmarshals stdout into []*models.BgpRoute. A mismatch between the agent's JSON output and this schema produces "failed to unmarshal bgp routes from <pod>: %w". It means the routes payload is not valid JSON of the expected BgpRoute array shape.

Source

Thrown at cilium-cli/bgp/routes.go:146

}

func (s *Status) fetchRoutesFromPod(ctx context.Context, fetchCmd []string, pod *corev1.Pod) ([]*models.BgpRoute, error) {
	output, errOutput, err := s.client.ExecInPodWithStderr(ctx, pod.Namespace, pod.Name, defaults.AgentContainerName, fetchCmd)
	if err != nil {
		var errStr string
		if errOutput.String() != "" {
			errStr = strings.TrimSpace(errOutput.String())
		} else {
			errStr = err.Error()
		}
		return nil, fmt.Errorf("failed to fetch bgp state from %s: (%s)", pod.Name, errStr)
	}

	bgpRoutes := make([]*models.BgpRoute, 0)

	err = json.Unmarshal(output.Bytes(), &bgpRoutes)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal bgp routes from %s: %w", pod.Name, err)
	}

	return bgpRoutes, nil
}

func (s *Status) writeRoutes(res map[string][]*models.BgpRoute, printPeer bool) error {
	if s.params.Output == status.OutputJSON {
		jsonStatus, err := json.MarshalIndent(res, "", " ")
		if err != nil {
			return err
		}
		fmt.Println(string(jsonStatus))
	} else {
		printRouteSummary(os.Stdout, res, printPeer)
	}

	return nil
}

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Align cilium-cli and Cilium agent versions so the `bgp routes -o json` schema matches models.BgpRoute.
  2. Inspect raw output via `kubectl exec <cilium-pod> -c cilium-agent -- cilium bgp routes ... -o json` and look for non-JSON text or unexpected field types.
  3. Confirm BGP is fully initialized on the node (peers established) so the agent returns a well-formed routes list.
  4. Retry after restarting the agent pod if it emitted a truncated/partial response.
Defensive patterns

Strategy: validation

Validate before calling

// pre-check the raw payload decodes as expected before relying on the CLI result:
RAW=$(kubectl exec <cilium-pod> -n kube-system -c cilium-agent -- cilium bgp routes available ipv4 unicast -o json)
echo "$RAW" | jq -e 'type == "array"' >/dev/null && echo OK || echo "unexpected payload shape"

Type guard

// Go: distinguish schema mismatch from malformed JSON
func isUnmarshalTypeError(err error) bool {
    var typeErr *json.UnmarshalTypeError
    return errors.As(err, &typeErr)
}
// if isUnmarshalTypeError(err): agent JSON shape differs from models.BgpRoute -> version skew

Try / catch

// Go
_, err := fetchRoutesFromPod(ctx, fetchCmd, pod)
if err != nil {
    var typeErr *json.UnmarshalTypeError
    if errors.As(err, &typeErr) {
        return fmt.Errorf("route schema mismatch (field %s): upgrade cilium-cli/agent to matching versions", typeErr.Field)
    }
    return err
}

Prevention

When it happens

Trigger: Running `cilium bgp routes ...` where the in-pod command exits 0 but its JSON cannot be decoded into []*models.BgpRoute (wrong field types, unexpected shape, extra non-JSON output on stdout).

Common situations: Cilium CLI and agent version skew (agent emits an older/newer route schema); BGP routes output containing warnings interleaved with JSON; the agent returning an empty or partial response due to a crashed BGP control plane while still exiting 0.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/d580fa7ad9c59bbe. Report an issue: GitHub.