juicedata/juicefs · error

mtime of key should be within 30 seconds, but got %s

Error message

mtime of key should be within 30 seconds, but got %s

What it means

In the `juicefs objbench` "list objects" case, after listing keys the code compares the listed object's mtime against the current time and requires it to be within a +/-30 second window. This message means the object storage backend reported a LastModified far from the time the key was just put, so the backend's object mtime is missing, stale, or skewed. It guards `ObjectStorage` implementations that must return accurate metadata.

Source

Thrown at cmd/objbench.go:909

			if err == nil {
				if len(objs) != 2 {
					return fmt.Errorf("list should return 2 keys, but got %d", len(objs))
				}
				if objs[0].Key() != "" {
					return fmt.Errorf("first key should be empty string, but got %s", objs[0].Key())
				}
				if objs[0].Size() != 0 {
					return fmt.Errorf("first object size should be 0, but got %d", objs[0].Size())
				}
				if objs[1].Key() != key {
					return fmt.Errorf("first key should be test, but got %s", objs[1].Key())
				}
				if objs[1].Size() != 5 {
					return fmt.Errorf("size of first key shold be 5, but got %v", objs[1].Size())
				}
				now := time.Now()
				if objs[1].Mtime().Before(now.Add(-30*time.Second)) || objs[1].Mtime().After(now.Add(time.Second*30)) {
					return fmt.Errorf("mtime of key should be within 30 seconds, but got %s", objs[1].Mtime().Sub(now))
				}
			} else {
				return fmt.Errorf("list failed: %s", err)
			}

			objs, err = listAll(ctx, blob, "", "test2", 1)
			if err != nil {
				return fmt.Errorf("list failed: %s", err)
			} else if len(objs) != 0 {
				return fmt.Errorf("list should not return anything, but got %d", len(objs))
			}
		} else {
			objs, err2 := listAll(ctx, blob, "", "", 1)
			if err2 == nil {
				if len(objs) != 1 {
					return fmt.Errorf("list should return 1 keys, but got %d", len(objs))
				}
				if objs[0].Key() != key {

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Check clock sync (NTP/chrony) between the client running objbench and the object storage service.
  2. Fix the ObjectStorage implementation's List/Head to return the real object LastModified instead of a zero or placeholder time.
  3. Verify the backend's list response parsing (timezone/epoch-seconds vs milliseconds) in pkg/object.
  4. Re-run objbench on the same host as the storage to rule out network-induced clock skew.

Example fix

// before: backend returns zero time on list
func (s *store) List(...) { ... object.NewFile(key, 5, time.Time{}) ... }
// after: propagate real LastModified
func (s *store) List(...) { ... object.NewFile(key, 5, modTime) ... }
Defensive patterns

Strategy: validation

Validate before calling

now := time.Now()
if m, ok := obj.(interface{ Mtime() time.Time }); ok {
    if m.Mtime().IsZero() {
        return fmt.Errorf("backend returned zero mtime for %s", obj.Key())
    }
}

Prevention

When it happens

Trigger: Running `juicefs objbench <object-storage-url>` against a backend whose list/Head result returns a zero, epoch, or heavily skewed mtime for the freshly written key "test"; also occurs when the client machine's clock differs from the storage service's clock by more than 30 seconds.

Common situations: Custom or third-party object storage implementations that hardcode mtime to zero or omit LastModified in LIST responses; NTP drift between the client and the storage node; backends returning mtime in a misparsed timezone.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/c637a3d5cd65040b. Report an issue: GitHub.