dgraph-io/dgraph · error

invalid untilDate %q: %v

Error message

invalid untilDate %q: %v

What it means

This error is thrown by buildBackupDateFilter in the Dgraph admin GraphQL API when the untilDate argument passed to the listBackups query cannot be parsed into a valid date/time. parseGraphQLDate is strict: it accepts a plain date (YYYY-MM-DD), a full RFC3339 datetime containing 'T', or a Unix timestamp, and any other format fails. The original parse error is embedded so the developer can see exactly which format check failed.

Source

Thrown at graphql/admin/list_backups.go:87

	}
	if input.LastNDays > 0 && input.SinceDate != "" {
		return filter, errors.Errorf("lastNDays and sinceDate are mutually exclusive")
	}
	if input.LastNDays > 0 {
		since := time.Now().UTC().AddDate(0, 0, -input.LastNDays).Truncate(24 * time.Hour)
		filter.Since = &since
	}
	if input.SinceDate != "" {
		t, err := parseGraphQLDate(input.SinceDate)
		if err != nil {
			return filter, errors.Errorf("invalid sinceDate %q: %v", input.SinceDate, err)
		}
		filter.Since = &t
	}
	if input.UntilDate != "" {
		t, err := parseGraphQLDate(input.UntilDate)
		if err != nil {
			return filter, errors.Errorf("invalid untilDate %q: %v", input.UntilDate, err)
		}
		var end time.Time
		if strings.Contains(input.UntilDate, "T") {
			// RFC3339 datetime: user gave an exact timestamp, respect it.
			end = t
		} else {
			// Plain date (YYYY-MM-DD): extend to end of that calendar day.
			end = t.Add(24*time.Hour - time.Millisecond)
		}
		filter.Until = &end
	}
	return filter, nil
}

// needsFullManifest returns true when the full manifest.json must be read.
// It is true when the caller explicitly sets fullManifest OR when the query
// selection set includes "groups", so existing queries that request groups
// continue to receive populated data without any input change.

View on GitHub (pinned to 759e242be6)

Solutions

  1. Reformat untilDate as RFC3339, e.g. '2024-03-15T10:00:00Z', or as a plain date '2024-03-15'.
  2. If passing a timestamp, send a Unix timestamp (integer string) which parseGraphQLDate accepts.
  3. Check the embedded %v error in the message to see exactly which parse stage failed and correct that specific part.
  4. Validate the string client-side with time.Parse(time.RFC3339, s) or new Date(value) before sending.
  5. If the input comes from a config or CLI flag, echo and fix the raw value; look for stray whitespace or quotes.

Example fix

// before
{ listBackups(input: { location: "s3://bucket", untilDate: "03/15/2024" }) }
// after
{ listBackups(input: { location: "s3://bucket", untilDate: "2024-03-15" }) }
Defensive patterns

Strategy: validation

Validate before calling

const RFC3339 = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}))?$/;
function isValidUntilDate(s) {
  if (!RFC3339.test(s)) return false;
  return !isNaN(new Date(s).getTime());
}
// pass only if isValidUntilDate(untilDate)

Type guard

function isRFC3339OrDate(s) {
  return typeof s === 'string' && (/^\d{4}-\d{2}-\d{2}$/.test(s) || !isNaN(Date.parse(s)) && s.includes('T'));
}

Try / catch

try {
  await listBackups({ untilDate });
} catch (e) {
  if (String(e.message).includes('invalid untilDate')) {
    // fall back to a plain YYYY-MM-DD or RFC3339 reformatted value and retry once
  }
}

Prevention

When it happens

Trigger: Calling the admin GraphQL listBackups mutation/query with untilDate set to a string that parseGraphQLDate rejects: e.g. '03/15/2024', '15-03-2024', 'yesterday', '2024/03/15', or a truncated datetime missing timezone like '2024-03-15T10:00'.

Common situations: Developers pass human-friendly dates or locale-formatted strings (US MM/DD/YYYY), omit the 'T'/timezone in RFC3339 timestamps, or pass values produced by non-Go date formatters with different separators. Frontends that format Date objects with toLocaleString are a frequent source.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/61ea42c58ac88f67. Report an issue: GitHub.