AlistGo/alist · error

expire_hours must be 0 or greater

Error message

expire_hours must be 0 or greater

What it means

Returned by resolveShareExpireAt (server/handles/share.go:286) when the request supplies a negative expire_hours and no explicit expire_at string. expire_hours is a shorthand that computes the expiry timestamp as now + expire_hours; 0 disables expiry. expire_at takes priority and is parsed instead when non-empty, so this error fires only on the hours path.

Source

Thrown at server/handles/share.go:286

	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() {
		return true
	}
	hash := sharePasswordHash(password, share.PasswordSalt)
	return subtle.ConstantTimeCompare([]byte(hash), []byte(share.PasswordHash)) == 1
}

func getShareAccessToken(c *gin.Context, fallback string) string {
	if fallback != "" {

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Send expire_hours: 0 to disable expiry
  2. If you computed the hours from a deadline, skip negative results and send 0
  3. Validate the field in the request builder before calling the API

Example fix

// before
{"expire_hours": -24}
// after
{"expire_hours": 0}
Defensive patterns

Strategy: validation

Validate before calling

if req.ExpireHours < 0 { return fmt.Errorf("expire_hours must be >= 0 (0 = no expiry)") }

Prevention

When it happens

Trigger: Share create/update with expire_hours: -1 in the body and an empty/absent expire_at; e.g. curl -d '{"path":"/f","expire_hours":-24}'.

Common situations: Clients using -1 to mean 'never expire' (this API uses 0); negative offsets computed from a target time already in the past.

Related errors


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