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
- Inspect handler.eventLog for the offending event and fix the code that recorded it so the proto message is fully valid.
- Regenerate proto code so generated Go types and the jsonpb library versions match.
- 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
- Only record fully initialized events onto handler.eventLog
- Keep proto generated code and golang/protobuf versions in sync
- Add a unit test that round-trips every registered event type through jsonpb
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
- marshalling event: %w
- marshalling old: %v
- unmarshalling new: %v
- marshalling configuration: %w
- marshaling new config: %w
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/7eddb07626f064a1.
Report an issue: GitHub.