{"record":{"id":"cbdf4a2b43821fef","repo":"dapr/dapr","slug":"error-parsing-s-due-time-w","errorCode":null,"errorMessage":"error parsing %s due time: %w","messagePattern":"error parsing (.+?) due time: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/actors/api/reminders.go","lineNumber":188,"sourceCode":"\n\tif len(m.Data) > 0 {\n\t\treq.Data, err = anypb.New(wrapperspb.Bytes(m.Data))\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal data: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc setReminderTimes(reminder *Reminder, dueTime string, period string, ttl string, now time.Time, logMsg string) (err error) {\n\t// Due time and registered time\n\treminder.RegisteredTime = now\n\treminder.DueTime = dueTime\n\tif dueTime != \"\" {\n\t\treminder.RegisteredTime, err = parseReminderTime(dueTime, &now)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing %s due time: %w\", logMsg, err)\n\t\t}\n\t}\n\n\t// Parse period and check correctness\n\treminder.Period, err = NewReminderPeriod(period)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid %s period: %w\", logMsg, err)\n\t}\n\n\t// Set expiration time if configured\n\tif ttl != \"\" {\n\t\treminder.ExpirationTime, err = parseReminderTime(ttl, &reminder.RegisteredTime)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error parsing %s TTL: %w\", logMsg, err)\n\t\t}\n\t\t// check if already expired\n\t\tif now.After(reminder.ExpirationTime) || reminder.RegisteredTime.After(reminder.ExpirationTime) {\n\t\t\treturn fmt.Errorf(\"%s %s has already expired: dueTime: %s TTL: %s\",","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/dapr/dapr/blob/74ad41702745709bb15fe2114ff693b8c59bc3cc/pkg/actors/api/reminders.go#L170-L206","documentation":"setReminderTimes parses dueTime with timeutils.ParseTime. That helper accepts either an RFC3339 timestamp (\"2025-01-02T15:04:05Z\") or a Go duration relative to now (\"90s\", \"1h\"). logMsg tells you whether the failing object is a reminder or a timer. An invalid dueTime string produces this error.","triggerScenarios":"CreateReminder/CreateTimer, or the HTTP APIs POST /actors/{type}/{id}/reminders and /timers, sends dueTime that is neither RFC3339 nor a Go duration: \"tomorrow\", \"1hour\", \"2025-01-02 15:04:05\" (missing T and zone), or an empty placeholder like \"null\".","commonSituations":"A date is formatted without the T separator or timezone offset. A relative value spells out a unit Go rejects. A UI passes free-text input straight into the request.","solutions":["Use an RFC3339 string with timezone (\"2025-01-02T15:04:05Z\") or a Go duration (\"5m\").","Omit dueTime (empty string) to fire at registration time.","Validate on the client with the same rule: try time.Parse(time.RFC3339, v), then time.ParseDuration(v)."],"exampleFix":"// before\n{\"dueTime\":\"2025-01-02 15:04:05\",\"period\":\"30s\"}\n\n// after\n{\"dueTime\":\"2025-01-02T15:04:05Z\",\"period\":\"30s\"}","handlingStrategy":"validation","validationCode":"import timeutils \"github.com/dapr/kit/time\"\n\nfunc validReminderTime(v string) bool {\n\tif v == \"\" {\n\t\treturn true\n\t}\n\tnow := time.Now()\n\t_, err := timeutils.ParseTime(v, &now)\n\treturn err == nil\n}","typeGuard":null,"tryCatchPattern":"if err := client.RegisterReminder(ctx, req); err != nil {\n\tif strings.Contains(err.Error(), \"due time\") {\n\t\t// bad dueTime string: fix input; parse failures are permanent\n\t}\n}","preventionTips":["Format absolute times with t.Format(time.RFC3339).","Test relative values with time.ParseDuration before sending.","Never retry a request with the same invalid string."],"tags":["go","dapr","actors","reminders","timers","time-parsing"],"backgroundTag":null,"analyzedSha":"74ad41702745709bb15fe2114ff693b8c59bc3cc","analyzedAt":"2026-08-16T04:22:26.543Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}