GoogleContainerTools/skaffold · error

marshalling event: %w

Error message

marshalling event: %w

What it means

SaveEventsToFile iterates the in-memory event log and serializes each event to JSON using golang/protobuf jsonpb.Marshaler before writing it to the file. This error wraps any failure from jsonpb Marshal when converting a proto event message to JSON, e.g. an event message that violates proto3 JSON mapping rules. It means one entry in handler.eventLog could not be serialized, so saving the event file aborts.

Source

Thrown at pkg/skaffold/event/v2/event.go:329

// SaveEventsToFile saves the current event log to the filepath provided
func SaveEventsToFile(fp string) error {
	handler.logLock.Lock()
	// Ensure that the filepath provided has the directories available when attemping to save the file.
	dir := filepath.Dir(fp)
	if err := os.MkdirAll(dir, 0700); err != nil {
		return fmt.Errorf("unable to create directory %q: %w", dir, err)
	}
	f, err := os.OpenFile(fp, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
	if err != nil {
		return fmt.Errorf("opening %s: %w", fp, err)
	}
	defer f.Close()
	marshaller := jsonpb.Marshaler{}
	for _, ev := range handler.eventLog {
		contents := bytes.NewBuffer([]byte{})
		if err := marshaller.Marshal(contents, ev); err != nil {
			return fmt.Errorf("marshalling event: %w", err)
		}
		if _, err := f.WriteString(contents.String() + "\n"); err != nil {
			return fmt.Errorf("writing string: %w", err)
		}
	}
	handler.logLock.Unlock()
	return nil
}

// SaveLastLog writes the output from the previous run to the specified filepath
func SaveLastLog(fp string) error {
	handler.logLock.Lock()
	defer handler.logLock.Unlock()

	// Create file to write logs to
	fp, err := lastLogFile(fp)
	if err != nil {
		return fmt.Errorf("getting last log file %w", err)

View on GitHub (pinned to a1189de023)

Solutions

  1. Inspect handler.eventLog for the offending event and fix the code that recorded it so the proto message is fully valid.
  2. Regenerate proto code so generated Go types and the jsonpb library versions match.
  3. Skip-and-log unmarshalable events instead of aborting the whole save, then re-run to see which event type is at fault.

Example fix

// before
if err := marshaller.Marshal(contents, ev); err != nil {
    return fmt.Errorf("marshalling event: %w", err)
}
// after
if err := marshaller.Marshal(contents, ev); err != nil {
    log.Entry(context.TODO()).Warnf("skipping unmarshalable event %T: %v", ev, err)
    continue
}
Defensive patterns

Strategy: try-catch

Validate before calling

for _, ev := range handler.eventLog {
    if ev == nil || ev.GetEvent() == nil {
        return fmt.Errorf("invalid event in log at index %d", i)
    }
}

Type guard

func isValidEvent(ev *proto.Event) bool {
    return ev != nil && ev.GetEvent() != nil
}

Try / catch

if err := event.SaveEventsToFile(path); err != nil {
    if strings.Contains(err.Error(), "marshalling event") {
        log.Warnf("event log contains unmarshalable entries: %v", err)
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Calling SaveEventsToFile when a recorded event in handler.eventLog cannot be marshaled by jsonpb.Marshaler{} — typically because the registered event's oneof payload is nil/invalid, an enum value is out of range, or a custom proto type fails its JSON mapping.

Common situations: Running TestSaveEventsToFile or a real session where a malformed/internally-inconsistent event was recorded; version skew where event protos were built with mismatched generated code; events enqueued with unset oneof cases.

Related errors


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/7eddb07626f064a1. Report an issue: GitHub.