{"record":{"id":"223a266e08f6afe0","repo":"argoproj/argo-workflows","slug":"workflow-s-expression-must-evaluate-to-a-string","errorCode":null,"errorMessage":"workflow %s expression must evaluate to a string, not a %T","messagePattern":"workflow (.+?) expression must evaluate to a string, not a %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/event/dispatch/operation.go","lineNumber":227,"sourceCode":"\t\twf.Annotations[annotationKey] = evalAnnotation\n\t}\n\treturn nil\n}\n\nfunc (o *Operation) evaluateStringExpression(statement string, errorInfo string) (string, error) {\n\tenv := exprenv.GetFuncMap(o.env)\n\tprogram, err := expr.Compile(statement, expr.Env(env))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to evaluate workflow %s expression: %w\", errorInfo, err)\n\t}\n\tresult, err := expr.Run(program, env)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to evaluate workflow %s expression: %w\", errorInfo, err)\n\t}\n\n\tv, ok := result.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"workflow %s expression must evaluate to a string, not a %T\", errorInfo, result)\n\t}\n\treturn v, nil\n}\n\nfunc expressionEnvironment(ctx context.Context, namespace, discriminator string, payload *wfv1.Item) (map[string]any, error) {\n\tsrc := map[string]any{\n\t\t\"namespace\":     namespace,\n\t\t\"discriminator\": discriminator,\n\t\t\"metadata\":      metaData(ctx),\n\t\t\"payload\":       payload,\n\t}\n\treturn jsonutil.Jsonify(src)\n}\n\nfunc metaData(ctx context.Context) map[string]any {\n\tmeta := make(map[string]any)\n\tmd, _ := metadata.FromIncomingContext(ctx)\n\tfor k, v := range md {","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/server/event/dispatch/operation.go#L209-L245","documentation":"Raised by Operation.evaluateStringExpression when a workflowMetadata name/generateName/label/annotation expression evaluates successfully but returns a non-string value (e.g. number, bool, map). Kubernetes metadata fields must be plain strings, so Argo refuses to coerce silently and aborts dispatch with the Go type (%T) it received. This is a distinct, deliberate type check after expr.Run, not a compile/run failure.","triggerScenarios":"EventBinding submit.workflowMetadata expression whose result type is not string, e.g. `payload.body.id` where id is a JSON number, `payload.body.enabled` returning bool, or an expression returning a nested object/array — anything that makes the `result.(string)` assertion fail.","commonSituations":"Event payloads with numeric IDs (int IDs from webhooks) used directly as label values; boolean flags used as annotations; expressions like `payload.body.tags` (array) pasted into labels; users assuming Argo stringifies like Workflow templates do — it does not in this path.","solutions":["Coerce the result to a string in the expression: `string(payload.body.id)`, `payload.body.enabled ? \"true\" : \"false\"`, or `json.stringify(...)` / sprig `toString`","Check the %T in the error message to learn which type the expression returned and adjust accordingly","Normalize the producer payload to emit string fields for metadata use","Add a validation step in CI that evaluates each workflowMetadata expression against a sample payload and asserts the result is a string"],"exampleFix":"// before (id is a JSON number)\nworkflowMetadata:\n  labels:\n    run-id: payload.body.id\n// after\nworkflowMetadata:\n  labels:\n    run-id: string(payload.body.id)","handlingStrategy":"type-guard","validationCode":"// Assert the expression yields a string before using it as metadata\nv, ok := result.(string)\nif !ok {\n    return fmt.Errorf(\"metadata expression must yield string, got %T\", result)\n}","typeGuard":"func isStringResult(result any) bool {\n    _, ok := result.(string)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Always wrap non-string payload fields with string(...), toString, or a ternary before using them in workflowMetadata","Remember labels/annotations/name must be K8s-valid strings (labels also have charset/length limits)","Add a schema test asserting each metadata expression returns a string for a sample payload","Keep numeric/boolean payload data out of metadata expressions unless explicitly coerced"],"tags":["expr","type-mismatch","event-dispatch","argo-workflows"],"backgroundTag":"expr-result-type-mismatch","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}