From 9b9f42cd5f2a02455714ed59c4190f1e165d5d70 Mon Sep 17 00:00:00 2001 From: devmanishofficial Date: Mon, 29 Dec 2025 22:02:10 +0530 Subject: [PATCH 1/3] fix(go): filter out non-genkit traces from dev ui Signed-off-by: devmanishofficial --- go/core/tracing/tracing.go | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/go/core/tracing/tracing.go b/go/core/tracing/tracing.go index 727625f75a..abfbe3d9e2 100644 --- a/go/core/tracing/tracing.go +++ b/go/core/tracing/tracing.go @@ -134,7 +134,8 @@ func Tracer() trace.Tracer { // such as one that writes to a file. func WriteTelemetryImmediate(client TelemetryClient) { e := newTelemetryServerExporter(client) - TracerProvider().RegisterSpanProcessor(sdktrace.NewSimpleSpanProcessor(e)) + filtered := &filteringExporter{exporter: e} + TracerProvider().RegisterSpanProcessor(sdktrace.NewSimpleSpanProcessor(filtered)) } // WriteTelemetryBatch adds a telemetry server to the global tracer provider. @@ -146,7 +147,8 @@ func WriteTelemetryImmediate(client TelemetryClient) { // and perform other cleanup. func WriteTelemetryBatch(client TelemetryClient) (shutdown func(context.Context) error) { e := newTelemetryServerExporter(client) - TracerProvider().RegisterSpanProcessor(sdktrace.NewBatchSpanProcessor(e)) + filtered := &filteringExporter{exporter: e} + TracerProvider().RegisterSpanProcessor(sdktrace.NewBatchSpanProcessor(filtered)) return TracerProvider().Shutdown } @@ -402,3 +404,33 @@ func SpanPath(ctx context.Context) string { func SpanTraceInfo(ctx context.Context) TraceInfo { return spanMetaKey.FromContext(ctx).TraceInfo } + +type filteringExporter struct { + exporter sdktrace.SpanExporter +} + +func (e *filteringExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) error { + var genkitSpans []sdktrace.ReadOnlySpan + for _, span := range spans { + if isGenkitSpan(span) { + genkitSpans = append(genkitSpans, span) + } + } + if len(genkitSpans) == 0 { + return nil + } + return e.exporter.ExportSpans(ctx, genkitSpans) +} + +func (e *filteringExporter) Shutdown(ctx context.Context) error { + return e.exporter.Shutdown(ctx) +} + +func isGenkitSpan(span sdktrace.ReadOnlySpan) bool { + for _, attr := range span.Attributes() { + if strings.HasPrefix(string(attr.Key), "genkit") { + return true + } + } + return false +} From 9ecb6f87af3e1ef2e83aa5d4b18631c884e26346 Mon Sep 17 00:00:00 2001 From: devmanishofficial Date: Mon, 29 Dec 2025 22:41:35 +0530 Subject: [PATCH 2/3] fix(go): implement Unwrap for GenkitError to support error chains Signed-off-by: devmanishofficial --- go/core/error.go | 36 ++++++++++++++++++++++++++---------- go/core/error_test.go | 23 +++++++++++++++++++++++ 2 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 go/core/error_test.go diff --git a/go/core/error.go b/go/core/error.go index ba70d7f76e..1861ef956b 100644 --- a/go/core/error.go +++ b/go/core/error.go @@ -37,11 +37,12 @@ type ReflectionError struct { // GenkitError is the base error type for Genkit errors. type GenkitError struct { - Message string `json:"message"` // Exclude from default JSON if embedded elsewhere - Status StatusName `json:"status"` - HTTPCode int `json:"-"` // Exclude from default JSON - Details map[string]any `json:"details"` // Use map for arbitrary details - Source *string `json:"source,omitempty"` // Pointer for optional + Message string `json:"message"` // Exclude from default JSON if embedded elsewhere + Status StatusName `json:"status"` + HTTPCode int `json:"-"` // Exclude from default JSON + Details map[string]any `json:"details"` // Use map for arbitrary details + Source *string `json:"source,omitempty"` // Pointer for optional + originalError error // The wrapped error, if any } // UserFacingError is the base error type for user facing errors. @@ -78,6 +79,13 @@ func NewError(status StatusName, message string, args ...any) *GenkitError { Message: fmt.Sprintf(msg, args...), } + // scan args for the last error to wrap it + for _, arg := range args { + if err, ok := arg.(error); ok { + ge.originalError = err + } + } + errStack := string(debug.Stack()) if errStack != "" { ge.Details = make(map[string]any) @@ -91,14 +99,22 @@ func (e *GenkitError) Error() string { return e.Message } +// Unwrap implements the standard error unwrapping interface. +// This allows errors.Is and errors.As to work with GenkitError. +func (e *GenkitError) Unwrap() error { + return e.originalError +} + // ToReflectionError returns a JSON-serializable representation for reflection API responses. func (e *GenkitError) ToReflectionError() ReflectionError { errDetails := &ReflectionErrorDetails{} - if stackVal, ok := e.Details["stack"].(string); ok { - errDetails.Stack = &stackVal - } - if traceVal, ok := e.Details["traceId"].(string); ok { - errDetails.TraceID = &traceVal + if e.Details != nil { + if stackVal, ok := e.Details["stack"].(string); ok { + errDetails.Stack = &stackVal + } + if traceVal, ok := e.Details["traceId"].(string); ok { + errDetails.TraceID = &traceVal + } } return ReflectionError{ Details: errDetails, diff --git a/go/core/error_test.go b/go/core/error_test.go new file mode 100644 index 0000000000..8361aa02c4 --- /dev/null +++ b/go/core/error_test.go @@ -0,0 +1,23 @@ +package core + +import ( + "errors" + "testing" +) + +func TestGenkitErrorUnwrap(t *testing.T) { + original := errors.New("original failure") + + // Use INTERNAL instead of StatusInternal + gErr := NewError(INTERNAL, "something happened: %v", original) + + // Verify errors.Is works (this is the most important check) + if !errors.Is(gErr, original) { + t.Errorf("expected errors.Is to return true, but got false") + } + + // Verify Unwrap works directly + if gErr.Unwrap() != original { + t.Errorf("Unwrap() returned wrong error") + } +} From d37d1ef6a8d5b5c43fe03a92b7b916b9792c370b Mon Sep 17 00:00:00 2001 From: devmanishofficial Date: Tue, 30 Dec 2025 00:15:30 +0530 Subject: [PATCH 3/3] fix: remove accidental telemetry changes and optimize error scan --- go/core/error.go | 8 ++++---- go/core/tracing/tracing.go | 36 ++---------------------------------- 2 files changed, 6 insertions(+), 38 deletions(-) diff --git a/go/core/error.go b/go/core/error.go index 1861ef956b..12671dd6c5 100644 --- a/go/core/error.go +++ b/go/core/error.go @@ -71,7 +71,6 @@ func (e *UserFacingError) Error() string { // NewError creates a new GenkitError with a stack trace. func NewError(status StatusName, message string, args ...any) *GenkitError { - // Prevents a compile-time warning about non-constant message. msg := message ge := &GenkitError{ @@ -79,10 +78,11 @@ func NewError(status StatusName, message string, args ...any) *GenkitError { Message: fmt.Sprintf(msg, args...), } - // scan args for the last error to wrap it - for _, arg := range args { - if err, ok := arg.(error); ok { + // scan args for the last error to wrap it (Iterate backwards) + for i := len(args) - 1; i >= 0; i-- { + if err, ok := args[i].(error); ok { ge.originalError = err + break } } diff --git a/go/core/tracing/tracing.go b/go/core/tracing/tracing.go index abfbe3d9e2..727625f75a 100644 --- a/go/core/tracing/tracing.go +++ b/go/core/tracing/tracing.go @@ -134,8 +134,7 @@ func Tracer() trace.Tracer { // such as one that writes to a file. func WriteTelemetryImmediate(client TelemetryClient) { e := newTelemetryServerExporter(client) - filtered := &filteringExporter{exporter: e} - TracerProvider().RegisterSpanProcessor(sdktrace.NewSimpleSpanProcessor(filtered)) + TracerProvider().RegisterSpanProcessor(sdktrace.NewSimpleSpanProcessor(e)) } // WriteTelemetryBatch adds a telemetry server to the global tracer provider. @@ -147,8 +146,7 @@ func WriteTelemetryImmediate(client TelemetryClient) { // and perform other cleanup. func WriteTelemetryBatch(client TelemetryClient) (shutdown func(context.Context) error) { e := newTelemetryServerExporter(client) - filtered := &filteringExporter{exporter: e} - TracerProvider().RegisterSpanProcessor(sdktrace.NewBatchSpanProcessor(filtered)) + TracerProvider().RegisterSpanProcessor(sdktrace.NewBatchSpanProcessor(e)) return TracerProvider().Shutdown } @@ -404,33 +402,3 @@ func SpanPath(ctx context.Context) string { func SpanTraceInfo(ctx context.Context) TraceInfo { return spanMetaKey.FromContext(ctx).TraceInfo } - -type filteringExporter struct { - exporter sdktrace.SpanExporter -} - -func (e *filteringExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) error { - var genkitSpans []sdktrace.ReadOnlySpan - for _, span := range spans { - if isGenkitSpan(span) { - genkitSpans = append(genkitSpans, span) - } - } - if len(genkitSpans) == 0 { - return nil - } - return e.exporter.ExportSpans(ctx, genkitSpans) -} - -func (e *filteringExporter) Shutdown(ctx context.Context) error { - return e.exporter.Shutdown(ctx) -} - -func isGenkitSpan(span sdktrace.ReadOnlySpan) bool { - for _, attr := range span.Attributes() { - if strings.HasPrefix(string(attr.Key), "genkit") { - return true - } - } - return false -}