From 42d9b663a80aa015bb069f804b2b3c2ded6dc10b Mon Sep 17 00:00:00 2001 From: David Ahmann Date: Sun, 22 Feb 2026 11:35:52 -0500 Subject: [PATCH] parser: stabilize unknown-property ordering in strict diagnostics (#17753) --- pkg/parser/schema_errors.go | 19 ++++++++++++++++--- pkg/parser/schema_errors_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/pkg/parser/schema_errors.go b/pkg/parser/schema_errors.go index b3e9d9ac635..00868f3c2ba 100644 --- a/pkg/parser/schema_errors.go +++ b/pkg/parser/schema_errors.go @@ -3,6 +3,7 @@ package parser import ( "fmt" "regexp" + "sort" "strings" ) @@ -211,9 +212,7 @@ func rewriteAdditionalPropertiesError(message string) string { match := re.FindStringSubmatch(message) if len(match) >= 2 { - properties := match[1] - // Clean up the property list and make it more readable - properties = strings.ReplaceAll(properties, "'", "") + properties := normalizeAdditionalPropertyList(match[1]) if strings.Contains(properties, ",") { return "Unknown properties: " + properties @@ -225,3 +224,17 @@ func rewriteAdditionalPropertiesError(message string) string { return message } + +func normalizeAdditionalPropertyList(raw string) string { + raw = strings.ReplaceAll(raw, "'", "") + parts := strings.Split(raw, ",") + cleaned := make([]string, 0, len(parts)) + for _, part := range parts { + trimmed := strings.TrimSpace(part) + if trimmed != "" { + cleaned = append(cleaned, trimmed) + } + } + sort.Strings(cleaned) + return strings.Join(cleaned, ", ") +} diff --git a/pkg/parser/schema_errors_test.go b/pkg/parser/schema_errors_test.go index 62e1c397c92..37608a391e4 100644 --- a/pkg/parser/schema_errors_test.go +++ b/pkg/parser/schema_errors_test.go @@ -274,3 +274,34 @@ func TestTranslateSchemaConstraintMessage(t *testing.T) { }) } } + +func TestRewriteAdditionalPropertiesErrorOrdering(t *testing.T) { + tests := []struct { + name string + in string + want string + }{ + { + name: "sorts multiple unknown properties", + in: "at '/safe-outputs': additional properties 'zeta', 'alpha', 'beta' not allowed", + want: "Unknown properties: alpha, beta, zeta", + }, + { + name: "sorts and trims unquoted list", + in: "additional properties zeta, alpha, beta not allowed", + want: "Unknown properties: alpha, beta, zeta", + }, + { + name: "single unknown property remains singular", + in: "additional property 'timeout_minutes' not allowed", + want: "Unknown property: timeout_minutes", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := rewriteAdditionalPropertiesError(tt.in) + assert.Equal(t, tt.want, got) + }) + } +}