From 3bf16656531adf60a2bb76429d03a4038bb6f0fb Mon Sep 17 00:00:00 2001 From: Nishant Bangarwa Date: Sun, 19 Jul 2026 12:08:17 +0530 Subject: [PATCH] fix: return error instead of panicking on invalid component variable `value` A component or canvas input variable with a value that structpb cannot convert (e.g. a bare date like 2024-01-01, which yaml.v3 decodes to a time.Time) caused a panic in ComponentVariableYAML.Proto that aborted the entire project parse. Convert via pbutil.ToValue, which handles time.Time and other YAML-decoded types, and return any remaining error as a normal parse error scoped to the file. --- runtime/parser/parse_component.go | 5 +++-- runtime/parser/parser_test.go | 37 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/runtime/parser/parse_component.go b/runtime/parser/parse_component.go index deced0272b10..ae30e389a706 100644 --- a/runtime/parser/parse_component.go +++ b/runtime/parser/parse_component.go @@ -5,6 +5,7 @@ import ( "fmt" runtimev1 "github.com/rilldata/rill/proto/gen/rill/runtime/v1" + "github.com/rilldata/rill/runtime/pkg/pbutil" "google.golang.org/protobuf/types/known/structpb" ) @@ -29,9 +30,9 @@ func (y *ComponentVariableYAML) Proto() (*runtimev1.ComponentVariable, error) { if y == nil { return nil, fmt.Errorf("is empty") } - val, err := structpb.NewValue(y.Value) + val, err := pbutil.ToValue(y.Value, nil) if err != nil { - panic(fmt.Errorf("invalid default value: %w", err)) + return nil, fmt.Errorf("invalid default value: %w", err) } return &runtimev1.ComponentVariable{ Name: y.Name, diff --git a/runtime/parser/parser_test.go b/runtime/parser/parser_test.go index 7482f6f9a7b7..efbcc8e72b42 100644 --- a/runtime/parser/parser_test.go +++ b/runtime/parser/parser_test.go @@ -1885,6 +1885,43 @@ rows: requireResourcesAndErrors(t, p, resources, nil) } +func TestComponentInputDateValue(t *testing.T) { + // Regression test: yaml.v3 decodes a bare date like 2024-01-01 into a time.Time, + // which structpb.NewValue rejects and previously caused a panic that aborted the entire parse. + ctx := context.Background() + repo := makeRepo(t, map[string]string{ + `rill.yaml`: ``, + `components/c1.yaml`: ` +type: component +markdown: + content: "Hello" +input: + - name: start + type: string + value: 2024-01-01 +`, + }) + + resources := []*Resource{ + { + Name: ResourceName{Kind: ResourceKindComponent, Name: "c1"}, + Paths: []string{"/components/c1.yaml"}, + ComponentSpec: &runtimev1.ComponentSpec{ + DisplayName: "C1", + Renderer: "markdown", + RendererProperties: must(structpb.NewStruct(map[string]any{"content": "Hello"})), + Input: []*runtimev1.ComponentVariable{ + {Name: "start", Type: "string", DefaultValue: structpb.NewStringValue("2024-01-01T00:00:00Z")}, + }, + }, + }, + } + + p, err := Parse(ctx, repo, "", "", "duckdb", true) + require.NoError(t, err) + requireResourcesAndErrors(t, p, resources, nil) +} + func TestCanvasTabGroups(t *testing.T) { ctx := context.Background() repo := makeRepo(t, map[string]string{