ipfs/kubo · error

mtime nanoseconds must be in range [1, 999999999]

Error message

mtime nanoseconds must be in range [1, 999999999]

What it means

Mtime sets a UnixFS timestamp (seconds plus nanoseconds, per the UnixFS spec's UnixTime metadata). The nanosecond sub-second field must be within [1, 999999999] (and is a uint32, so negatives are impossible); a larger value is meaningless in Go's time representation and is rejected.

Source

Thrown at core/coreiface/options/unixfs.go:413

	return func(settings *UnixfsAddSettings) error {
		settings.PreserveMtime = enable
		return nil
	}
}

// Mode represents a unix file mode
func (unixfsOpts) Mode(mode os.FileMode) UnixfsAddOption {
	return func(settings *UnixfsAddSettings) error {
		settings.Mode = mode
		return nil
	}
}

// Mtime represents a unix file mtime
func (unixfsOpts) Mtime(seconds int64, nsecs uint32) UnixfsAddOption {
	return func(settings *UnixfsAddSettings) error {
		if nsecs > 999999999 {
			return errors.New("mtime nanoseconds must be in range [1, 999999999]")
		}
		settings.Mtime = time.Unix(seconds, int64(nsecs))
		return nil
	}
}

// IncludeEmptyDirs tells the adder to include empty directories in the DAG
func (unixfsOpts) IncludeEmptyDirs(include bool) UnixfsAddOption {
	return func(settings *UnixfsAddSettings) error {
		settings.IncludeEmptyDirs = include
		settings.IncludeEmptyDirsSet = true
		return nil
	}
}

View on GitHub (pinned to 329838acdf)

Solutions

  1. Pass the sub-second remainder as nanoseconds: time.Unix(sec, 0) then t.Nanosecond() (always < 1e9), not the raw t.UnixNano()
  2. If your source is milliseconds, use nsecs = ms*1e6; for microseconds, use µs*1e3 — and verify the result stays under 1e9
  3. If you only have second precision, pass 0 for nsecs

Example fix

// before
options.Unixfs.Mtime(t.Unix(), uint32(t.UnixNano())) // nsecs out of range

// after
options.Unixfs.Mtime(t.Unix(), uint32(t.Nanosecond()))
Defensive patterns

Strategy: validation

Validate before calling

func safeMtime(t time.Time) (int64, uint32, error) {
    ns := t.Nanosecond() // always in [0, 999999999]
    if ns < 0 {
        return 0, 0, errors.New("negative nanoseconds")
    }
    return t.Unix(), uint32(ns), nil
}
sec, nsec, err := safeMtime(t)
if err != nil {
    return err
}
opt := options.Unixfs.Mtime(sec, nsec)

Type guard

func nsecsInRange(n uint32) bool {
    return n <= 999999999
}

Try / catch

opt := options.Unixfs.Mtime(sec, nsec)
if err := apply(opt); err != nil {
    if strings.Contains(err.Error(), "mtime nanoseconds") {
        // fall back to second precision
        err = apply(options.Unixfs.Mtime(sec, 0))
    }
    if err != nil {
        return err
    }
}

Prevention

When it happens

Trigger: Calling options.Unixfs.Mtime(seconds, nsecs) with nsecs > 999999999 — e.g. Mtime(t.Unix(), t.Nanosecond()*1000) (mixing micro- and nanoseconds), or hardcoding 1000000000.

Common situations: Multiplying milliseconds or microseconds by the wrong factor (ms*1e6 vs µs*1e3) before passing; copying a full nanosecond-precision duration instead of its sub-second remainder; hand-rolled timestamp parsing producing out-of-range fractions.

Related errors


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/e332584805146cdf. Report an issue: GitHub.