AlistGo/alist · error
invalid expire_at
Error message
invalid expire_at
What it means
Returned by parseShareExpireAt (server/handles/share.go:278) when the expire_at string of a share request matches none of the accepted layouts: RFC3339 (e.g. 2026-08-15T12:00:00Z), 2006-01-02T15:04:05, 2006-01-02T15:04, or 2006-01-02 15:04:05 — the last three parsed in the server's local timezone. The field is optional; an empty string means 'no expiry', so only a non-empty unparseable string triggers this error.
Source
Thrown at server/handles/share.go:278
func parseShareExpireAt(raw string) (*time.Time, error) {
value := strings.TrimSpace(raw)
if value == "" {
return nil, nil
}
if parsed, err := time.Parse(time.RFC3339, value); err == nil {
return &parsed, nil
}
layouts := []string{
"2006-01-02T15:04:05",
"2006-01-02T15:04",
"2006-01-02 15:04:05",
}
for _, layout := range layouts {
if parsed, err := time.ParseInLocation(layout, value, time.Local); err == nil {
return &parsed, nil
}
}
return nil, fmt.Errorf("invalid expire_at")
}
func resolveShareExpireAt(expireAt string, expireHours int64) (*time.Time, error) {
if strings.TrimSpace(expireAt) != "" {
return parseShareExpireAt(expireAt)
}
if expireHours < 0 {
return nil, fmt.Errorf("expire_hours must be 0 or greater")
}
if expireHours == 0 {
return nil, nil
}
expires := time.Now().Add(time.Duration(expireHours) * time.Hour)
return &expires, nil
}
func sharePasswordMatched(share *model.Share, password string) bool {
if !share.HasPassword() {View on GitHub (pinned to 843d9dc814)
Solutions
- Use full RFC3339 with an explicit offset, e.g. 2026-08-15T12:00:00Z
- Or include a time component in one of the three local layouts (2026-08-15T12:00:00)
- If you only need a relative expiry, drop expire_at and send expire_hours instead
Example fix
// before
{"expire_at": "2026/08/15 14:00"}
// after
{"expire_at": "2026-08-15T14:00:00Z"} Defensive patterns
Strategy: validation
Validate before calling
layouts := []string{time.RFC3339, "2006-01-02T15:04:05", "2006-01-02T15:04", "2006-01-02 15:04:05"}
func validExpireAt(s string) bool {
s = strings.TrimSpace(s)
if s == "" { return true }
for _, l := range layouts { if _, err := time.Parse(l, s); err == nil { return true } }
return false
} Prevention
- Standardize on RFC3339 with an explicit UTC offset in clients
- Prefer expire_hours for relative deadlines
- Remember date-only strings are rejected — a time component is required
When it happens
Trigger: Share create/update with expire_at="2026/08/15" (slashes), "2026-08-15" (date only, no time), "tomorrow", or an impossible date like "2026-02-30".
Common situations: Date pickers emitting locale-specific formats; clients copying a date-only value; timezone suffixes that are not valid RFC3339 offsets.
Related errors
- share_id must be 1-32 characters of letters, numbers, unders
- access_limit must be 0 or greater
- expire_hours must be 0 or greater
- file share does not support nested path
- paths is required
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/51b76e5847ca969c.
Report an issue: GitHub.