wavetermdev/waveterm · error

circular file cannot be ijson

Error message

circular file cannot be ijson

What it means

IJson files carry per-item JSON metadata that has no place in a circular ring buffer layout, so the combination is structurally unsupported. MakeFile rejects Circular && IJson early to avoid creating a file whose format invariants conflict.

Source

Thrown at pkg/filestore/blockstore.go:123

type FileData struct {
	ZoneId  string `json:"zoneid"`
	Name    string `json:"name"`
	PartIdx int    `json:"partidx"`
	Data    []byte `json:"data"`
}

func (FileData) UseDBMap() {}

// synchronous (does not interact with the cache)
func (s *FileStore) MakeFile(ctx context.Context, zoneId string, name string, meta wshrpc.FileMeta, opts wshrpc.FileOpts) error {
	if opts.MaxSize < 0 {
		return fmt.Errorf("max size must be non-negative")
	}
	if opts.Circular && opts.MaxSize <= 0 {
		return fmt.Errorf("circular file must have a max size")
	}
	if opts.Circular && opts.IJson {
		return fmt.Errorf("circular file cannot be ijson")
	}
	if opts.Circular {
		if opts.MaxSize%partDataSize != 0 {
			opts.MaxSize = (opts.MaxSize/partDataSize + 1) * partDataSize
		}
	}
	if opts.IJsonBudget > 0 && !opts.IJson {
		return fmt.Errorf("ijson budget requires ijson")
	}
	if opts.IJsonBudget < 0 {
		return fmt.Errorf("ijson budget must be non-negative")
	}
	return withLock(s, zoneId, name, func(entry *CacheEntry) error {
		if entry.File != nil {
			return fs.ErrExist
		}
		now := time.Now().UnixMilli()
		file := &WaveFile{

View on GitHub (pinned to a4447c1563)

Solutions

  1. Choose one mode: keep IJson=false if you need a fixed-size circular file, or keep Circular=false if you need ijson.
  2. If you need both bounded size and structured JSON records, implement trimming at the application level instead of circular mode.
  3. Split into two files: a circular file for raw data plus a separate ijson file for metadata.

Example fix

// before
opts := wshrpc.FileOpts{Circular: true, IJson: true}
// after
opts := wshrpc.FileOpts{Circular: true, IJson: false} // ring-buffer mode only
Defensive patterns

Strategy: validation

Validate before calling

func validModeOpts(opts wshrpc.FileOpts) bool {
	return !(opts.Circular && opts.IJson)
}
if !validModeOpts(opts) {
	return fmt.Errorf("circular and ijson are mutually exclusive")
}

Try / catch

if err := store.MakeFile(ctx, zoneId, name, meta, opts); err != nil {
	if strings.Contains(err.Error(), "circular file cannot be ijson") {
		opts.IJson = false // prefer circular mode
		err = store.MakeFile(ctx, zoneId, name, meta, opts)
	}
	if err != nil {
		return err
	}
}

Prevention

When it happens

Trigger: Calling MakeFile with both opts.Circular = true and opts.IJson = true — e.g. merging option sets where one enables circular buffering and another enables ijson mode.

Common situations: Building FileOpts from user preferences where both toggles are independently exposed; a caller migrating an ijson file to circular for retention without realizing the formats are mutually exclusive; copy-pasted opts structs accumulating flags.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/560504e8fab83e69. Report an issue: GitHub.