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

  1. Use full RFC3339 with an explicit offset, e.g. 2026-08-15T12:00:00Z
  2. Or include a time component in one of the three local layouts (2026-08-15T12:00:00)
  3. 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

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


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/51b76e5847ca969c. Report an issue: GitHub.