{"record":{"id":"c3bb5bd8cedbaf28","repo":"temporalio/temporal","slug":"w-s-c3bb5b","errorCode":null,"errorMessage":"%w: %s","messagePattern":"%w: %s","errorType":"exception","errorClass":"sadefs.ErrInvalidString","httpStatus":null,"severity":"error","filePath":"common/searchattribute/sadefs/encode_value.go","lineNumber":81,"sourceCode":"\tcase enumspb.INDEXED_VALUE_TYPE_TEXT:\n\t\treturn validateStrings(decodeValueTyped[string](value, allowList))\n\tcase enumspb.INDEXED_VALUE_TYPE_KEYWORD_LIST:\n\t\treturn validateStrings(decodeValueTyped[[]string](value, false))\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"%w: %v\", ErrInvalidType, t)\n\t}\n}\n\nfunc validateStrings(anyValue any, err error) (any, error) {\n\tif err != nil {\n\t\treturn anyValue, err\n\t}\n\n\t// validate strings\n\tswitch value := anyValue.(type) {\n\tcase string:\n\t\tif !utf8.ValidString(value) {\n\t\t\treturn nil, fmt.Errorf(\"%w: %s\", ErrInvalidString, value)\n\t\t}\n\tcase []string:\n\t\tfor _, item := range value {\n\t\t\tif !utf8.ValidString(item) {\n\t\t\t\treturn nil, fmt.Errorf(\"%w: %s\", ErrInvalidString, item)\n\t\t\t}\n\t\t}\n\t}\n\treturn anyValue, err\n}\n\n// decodeValueTyped tries to decode to the given type.\n// If the input is a list and allowList is false, then it will return only the first element.\n// If the input is a list and allowList is true, then it will return the decoded list.\n//\n//nolint:revive // allowList is a control flag\nfunc decodeValueTyped[T any](value *commonpb.Payload, allowList bool) (any, error) {\n\t// At first, it tries to decode to pointer of actual type (i.e. `*string` for `string`).","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/searchattribute/sadefs/encode_value.go#L63-L99","documentation":"validateStrings wraps sadefs.ErrInvalidString when a decoded string search attribute value contains invalid UTF-8. The visibility store (Elasticsearch/SQL) cannot safely index or compare non-UTF-8 bytes, so decoding rejects them early with the offending value in the message.","triggerScenarios":"DecodeValue on a Keyword, Text, or single-string payload whose bytes do not form valid UTF-8 — typically a payload written by a client that did not validate its string input.","commonSituations":"Binary data accidentally placed into a Keyword attribute; strings built from raw network bytes or wrong charset encodings (e.g. Latin-1) before being attached to a workflow.","solutions":["Ensure the producer encodes strings as UTF-8 before attaching them as search attributes.","Sanitize or transcode the offending value (the invalid string is included in the error message) at the workflow-start/memo layer.","Use utf8.ValidString to pre-validate values before calling EncodeValue/DecodeValue."],"exampleFix":"// before\npayload, err := sadefs.EncodeValue(rawBytesAsString, false)\n// after\nif !utf8.ValidString(s) {\n    s = strings.ToValidUTF8(s, \"\\uFFFD\")\n}\npayload, err := sadefs.EncodeValue(s, false)","handlingStrategy":"validation","validationCode":"if !utf8.ValidString(s) {\n    return fmt.Errorf(\"search attribute value is not valid UTF-8\")\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, sadefs.ErrInvalidString) { /* sanitize and re-encode */ }","preventionTips":["Run utf8.ValidString on all external strings before attaching as attributes","Transcode non-UTF-8 input with strings.ToValidUTF8","Never put raw binary data into Keyword/Text attributes"],"tags":["go","search-attributes","utf8","string-validation"],"backgroundTag":"invalid-utf8-string","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}