{"record":{"id":"c0617294b59a4fe0","repo":"amir20/dozzle","slug":"failed-to-compile-metric-expression-w","errorCode":null,"errorMessage":"failed to compile metric expression: %w","messagePattern":"failed to compile metric expression: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notification/manager.go","lineNumber":218,"sourceCode":"\t\t\t\t\tif exprStr != \"\" {\n\t\t\t\t\t\tprogram, err := expr.Compile(exprStr, expr.Env(types.NotificationLog{}))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tupdateErr = fmt.Errorf(\"failed to compile log expression: %w\", err)\n\t\t\t\t\t\t\treturn nil, xsync.CancelOp\n\t\t\t\t\t\t}\n\t\t\t\t\t\tupdated.LogExpression = exprStr\n\t\t\t\t\t\tupdated.LogProgram = program\n\t\t\t\t\t} else {\n\t\t\t\t\t\tupdated.LogExpression = \"\"\n\t\t\t\t\t\tupdated.LogProgram = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase \"metricExpression\":\n\t\t\t\tif exprStr, ok := value.(string); ok {\n\t\t\t\t\tif exprStr != \"\" {\n\t\t\t\t\t\tprogram, err := expr.Compile(exprStr, expr.Env(types.NotificationStat{}))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tupdateErr = fmt.Errorf(\"failed to compile metric expression: %w\", err)\n\t\t\t\t\t\t\treturn nil, xsync.CancelOp\n\t\t\t\t\t\t}\n\t\t\t\t\t\tupdated.MetricExpression = exprStr\n\t\t\t\t\t\tupdated.MetricProgram = program\n\t\t\t\t\t} else {\n\t\t\t\t\t\tupdated.MetricExpression = \"\"\n\t\t\t\t\t\tupdated.MetricProgram = nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tcase \"eventExpression\":\n\t\t\t\tif exprStr, ok := value.(string); ok {\n\t\t\t\t\tif exprStr != \"\" {\n\t\t\t\t\t\tprogram, err := expr.Compile(exprStr, expr.Env(types.NotificationEvent{}))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\tupdateErr = fmt.Errorf(\"failed to compile event expression: %w\", err)\n\t\t\t\t\t\t\treturn nil, xsync.CancelOp\n\t\t\t\t\t\t}\n\t\t\t\t\t\tupdated.EventExpression = exprStr","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/notification/manager.go#L200-L236","documentation":"For a non-empty \"metricExpression\" update, Manager.UpdateSubscription compiles the string with expr against the types.NotificationStat environment. Compilation errors (bad syntax, fields absent from NotificationStat, type-invalid comparisons) are wrapped in this error and the Compute op cancels, so the subscription keeps its previous metric expression.","triggerScenarios":"Updating a subscription with \"metricExpression\" that expr cannot compile against NotificationStat: misspelled stat fields (cpuPct vs actual names), comparing strings to numbers, or invalid operator usage.","commonSituations":"Users writing CPU/memory threshold rules with guessed field names or unit-confused comparisons (e.g. comparing a percentage field against bytes), or syntax copied from other alerting systems.","solutions":["Read the wrapped expr.Compile error to find the failing expression part.","Use only fields defined on types.NotificationStat and match their types/units.","Pass an empty string to clear the metric expression rather than an invalid placeholder.","Test the threshold expression with sample stat values before saving."],"exampleFix":"// before (wrong field name)\n{\"metricExpression\": \"cpuPercent > 90\"}\n// after\n{\"metricExpression\": \"cpu > 0.9\"}","handlingStrategy":"validation","validationCode":"if exprStr, ok := updates[\"metricExpression\"].(string); ok && exprStr != \"\" {\n    if _, err := expr.Compile(exprStr, expr.Env(types.NotificationStat{})); err != nil {\n        return fmt.Errorf(\"invalid metricExpression: %w\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := manager.UpdateSubscription(id, updates); err != nil {\n    if strings.Contains(err.Error(), \"failed to compile metric expression\") {\n        return fmt.Errorf(\"fix metric expression against NotificationStat fields: %w\", err)\n    }\n    return err\n}","preventionTips":["Match metric field names and units to types.NotificationStat exactly.","Compare percentage fields against 0-1 or 0-100 consistently with the struct definition.","Validate thresholds against real sample stats before saving."],"tags":["expression","validation","metrics"],"backgroundTag":"expression-compilation-failed","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}