{"record":{"id":"90c9a674f0e0b879","repo":"pulumi/pulumi","slug":"failed-to-parse-before-as-duration-or-timestamp","errorCode":null,"errorMessage":"failed to parse --before as duration or timestamp: %w","messagePattern":"failed to parse --before as duration or timestamp: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cmd/pulumi/logs/remove.go","lineNumber":139,"sourceCode":"\tif !all && before == \"\" && stackName == \"\" {\n\t\tif !cmdutil.Interactive() {\n\t\t\treturn nil, errors.New(\n\t\t\t\t\"cannot prompt for a log file in non-interactive mode; \" +\n\t\t\t\t\t\"pass --all, --before, or --stack\")\n\t\t}\n\t\tentry, err := chooseLogToRemove(logsDir)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn []logEntry{entry}, nil\n\t}\n\n\tvar beforeTime *time.Time\n\tif before != \"\" {\n\t\tvar err error\n\t\tbeforeTime, err = parseSince(before, time.Now())\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse --before as duration or timestamp: %w\", err)\n\t\t}\n\t}\n\n\tentries, err := listLogs(logsDir)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn filterLogs(entries, stackName, beforeTime), nil\n}\n\nfunc filterLogs(entries []logEntry, stackName string, beforeTime *time.Time) []logEntry {\n\tvar matches []logEntry\n\tfor _, e := range entries {\n\t\tif stackName != \"\" && e.stack != stackName {\n\t\t\tcontinue\n\t\t}\n\t\tif beforeTime != nil && !e.timestamp.Before(*beforeTime) {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/pkg/cmd/pulumi/logs/remove.go#L121-L157","documentation":"The --before flag of `pulumi logs remove` (pkg/cmd/pulumi/logs/remove.go:139) accepts a Go duration (e.g. '24h') or a timestamp (RFC3339, date, or Unix). The value is passed to parseSince (pkg/cmd/pulumi/logs/logs.go:226), which uses the moby-derived getTimestamp parser; when neither format matches, the underlying error is wrapped with this message.","triggerScenarios":"`pulumi logs remove --before <value>` where value fails time.ParseDuration and all timestamp layouts: e.g. --before 24H (uppercase), --before 1d (Go durations have no days), --before yesterday, --before \"Jan 1 2026\", or a negative range with hyphens that can't parse.","commonSituations":"Copying '1d' or '2w' from other CLIs that accept day/week units; locale-formatted dates; quotes stripped by shell leaving ambiguous values like 2026-13-45; forgetting that durations are Go-style (h/m/s only).","solutions":["Use a Go duration such as 24h, 72h, or 30m (no 'd' or 'w' units)","Use an absolute timestamp: RFC3339 (2026-01-01T00:00:00Z), a plain date (2026-01-01), or a Unix epoch value","Quote the value in the shell if it contains spaces or special characters","Verify with `pulumi logs --since <same-value>` which accepts the identical format and shows the same parse error"],"exampleFix":"# before\npulumi logs remove --before 30d\n# after\npulumi logs remove --before 720h   # 30 days as a Go duration\n# or\npulumi logs remove --before 2026-01-01","handlingStrategy":"validation","validationCode":"# Go-side pre-validation using the same semantics\nif _, err := time.ParseDuration(v); err != nil {\n    if _, err2 := time.Parse(time.RFC3339, v); err2 != nil {\n        if _, _, err3 := time.Parse(\"2006-01-02\", v); err3 != nil {\n            return fmt.Errorf(\"--before must be a Go duration (720h) or timestamp: %v\", v)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use only Go duration units (s, m, h) — 1d/1w are invalid; convert days to hours","Prefer absolute dates like 2026-01-01 for anything older than a few days","Smoke-test the value with `pulumi logs --since <value>` first"],"tags":["cli","flag-parsing","duration","timestamp","pulumi"],"backgroundTag":"invalid-duration-format","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}