dutchcoders/transfer.sh · warning

maxDate expired

Error message

maxDate expired

What it means

checkMetadata also enforces an optional expiry date stored in the file's metadata. If the metadata has a non-zero MaxDate and the current time is after it, the server refuses to serve the file and returns this error. It means the upload's time-to-live, as chosen by the sender, has elapsed.

Source

Thrown at server/handlers.go:888

func (s *Server) checkMetadata(ctx context.Context, token, filename string, increaseDownload bool) (metadata, error) {
	s.lock(token, filename)
	defer s.unlock(token, filename)

	var metadata metadata

	r, _, err := s.storage.Get(ctx, token, fmt.Sprintf("%s.metadata", filename), nil)
	defer storage.CloseCheck(r)

	if err != nil {
		return metadata, err
	}

	if err := json.NewDecoder(r).Decode(&metadata); err != nil {
		return metadata, err
	} else if metadata.MaxDownloads != -1 && metadata.Downloads >= metadata.MaxDownloads {
		return metadata, errors.New("maxDownloads expired")
	} else if !metadata.MaxDate.IsZero() && time.Now().After(metadata.MaxDate) {
		return metadata, errors.New("maxDate expired")
	} else if metadata.MaxDownloads != -1 && increaseDownload {
		// todo(nl5887): mutex?

		// update number of downloads
		metadata.Downloads++

		buffer := &bytes.Buffer{}
		if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
			return metadata, errors.New("could not encode metadata")
		} else if err := s.storage.Put(ctx, token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
			return metadata, errors.New("could not save metadata")
		}
	}

	return metadata, nil
}

func (s *Server) checkDeletionToken(ctx context.Context, deletionToken, token, filename string) error {

View on GitHub (pinned to c37bfd9579)

Solutions

  1. Request the sender re-upload and share a fresh link with a later Max-Date.
  2. Upload with a longer expiry (larger --purge-days / appropriate Max-Date header) when the link must live longer.
  3. Verify server clock/NTP sync if files expire sooner than expected.
  4. If you control the deployment, purge/expiry policy can be tuned in checkMetadata or the purge job.

Example fix

// before
curl -H 'Max-Date: 2026-01-01T00:00:00Z' -T f https://host/f  # already past
// after
curl -H 'Max-Date: 2026-12-31T00:00:00Z' -T f https://host/f
Defensive patterns

Strategy: try-catch

Try / catch

resp, err := http.Get(url)
if err == nil {
	body, _ := io.ReadAll(resp.Body)
	if strings.Contains(string(body), "maxDate expired") {
		// link expired: ask sender to re-upload
	}
}

Prevention

When it happens

Trigger: Any download request (GET/HEAD/preview/zip/tar/tar.gz) for a token whose metadata contains MaxDate in the past, e.g. an upload created with a Max-Date header (or purge days) that has since passed.

Common situations: Recipient opens a shared link after the expiry window set by the sender; clocks skewed between server and client making a link appear expired early; very short expirations (minutes) combined with email/social delays.

Related errors


AI-assisted analysis of dutchcoders/transfer.sh@c37bfd9579 (2026-09-05). Data as JSON: /api/errors/a95003c9354dca1e. Report an issue: GitHub.