{"record":{"id":"1248d32975db0733","repo":"SigNoz/signoz","slug":"not-a-valid-ttl-duration-v","errorCode":null,"errorMessage":"not a valid TTL duration %v","messagePattern":"not a valid TTL duration (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/query-service/app/parser.go","lineNumber":443,"sourceCode":"\t// make sure either of the query params are present\n\ttypeTTL := r.URL.Query().Get(\"type\")\n\tdelDuration := r.URL.Query().Get(\"duration\")\n\tcoldStorage := r.URL.Query().Get(\"coldStorage\")\n\ttoColdDuration := r.URL.Query().Get(\"toColdDuration\")\n\n\tif len(typeTTL) == 0 || len(delDuration) == 0 {\n\t\treturn nil, fmt.Errorf(\"type and duration param cannot be empty from the query\")\n\t}\n\n\t// Validate the type parameter\n\tif typeTTL != retentiontypes.TraceTTL && typeTTL != retentiontypes.MetricsTTL && typeTTL != retentiontypes.LogsTTL {\n\t\treturn nil, fmt.Errorf(\"type param should be metrics|traces|logs, got %v\", typeTTL)\n\t}\n\n\t// Validate the TTL duration.\n\tdurationParsed, err := time.ParseDuration(delDuration)\n\tif err != nil || durationParsed.Seconds() <= 0 {\n\t\treturn nil, fmt.Errorf(\"not a valid TTL duration %v\", delDuration)\n\t}\n\n\tvar toColdParsed time.Duration\n\n\t// If some cold storage is provided, validate the cold storage move TTL.\n\tif len(coldStorage) > 0 {\n\t\ttoColdParsed, err = time.ParseDuration(toColdDuration)\n\t\tif err != nil || toColdParsed.Seconds() <= 0 {\n\t\t\treturn nil, fmt.Errorf(\"not a valid toCold TTL duration %v\", toColdDuration)\n\t\t}\n\t\tif toColdParsed.Seconds() != 0 && toColdParsed.Seconds() >= durationParsed.Seconds() {\n\t\t\treturn nil, fmt.Errorf(\"delete TTL should be greater than cold storage move TTL\")\n\t\t}\n\t}\n\n\treturn &retentiontypes.TTLParams{\n\t\tType:                  typeTTL,\n\t\tDelDuration:           int64(durationParsed.Seconds()),","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/SigNoz/signoz/blob/5069bf80b08f1f00d7e014eccc09902f9871004f/pkg/query-service/app/parser.go#L425-L461","documentation":"The 'duration' query parameter must be a valid Go duration string parseable by time.ParseDuration with a positive value (seconds > 0). Zero, negative, or malformed durations are rejected before the TTL is applied.","triggerScenarios":"Passing duration=0, duration=-24h, duration=72 (bare number, no unit), or duration=forever to setTTL.","commonSituations":"Passing a plain number of hours instead of a Go duration string; sending milliseconds as '72000' without a unit; frontend sending seconds as an integer.","solutions":["Use Go duration syntax with a unit, e.g. duration=72h or duration=48h0m0s","Ensure the value is strictly positive","If sending from code, format with time.Duration.String()"],"exampleFix":"// before\n?type=traces&duration=72\n// after\n?type=traces&duration=72h","handlingStrategy":"validation","validationCode":"d, err := time.ParseDuration(durationStr)\nif err != nil || d <= 0 { return fmt.Errorf(\"duration must be a positive Go duration like 72h\") }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always format durations with time.Duration.String()","Never send bare integers as durations"],"tags":["signoz","retention","ttl","duration-parsing","go-duration"],"backgroundTag":"invalid-duration-format","analyzedSha":"5069bf80b08f1f00d7e014eccc09902f9871004f","analyzedAt":"2026-08-28T06:22:12.824Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}