thanos-io/thanos · error

failed to parse as JSON

Error message

failed to parse %s as JSON: %q

What it means

ReadMetaFile parses a shipper meta file (JSON) from disk and wraps any json.Unmarshal failure with this message, including the file path and raw content. It is thrown because the meta file bytes are not valid JSON (or not decodable into shipper.Meta), so the shipper cannot determine which blocks were uploaded.

Solutions

  1. Inspect the file contents (`cat <path>`) and fix or regenerate the corrupted meta.json.
  2. Delete the corrupt meta file and re-run the shipper Sync so it recreates meta state from the object store.
  3. Verify the process writing the meta file completes writes atomically (write to temp file then rename) to prevent truncation.
  4. Check disk health and available space if corruption recurs.

Example fix

// before
m, err := shipper.ReadMetaFile(path)
// after
if _, err := os.Stat(path); err != nil { return err }
b, _ := os.ReadFile(path)
if !json.Valid(b) {
    // regenerate or restore meta file before parsing
    return fmt.Errorf("meta file %s is not valid JSON", path)
}
m, err := shipper.ReadMetaFile(path)
Defensive patterns

Strategy: validation

Validate before calling

b, err := os.ReadFile(path)
if err != nil { return err }
if !json.Valid(b) {
    return fmt.Errorf("meta file %s is not valid JSON; regenerate or delete it", path)
}

Try / catch

m, err := shipper.ReadMetaFile(path)
if err != nil {
    var corrupted = strings.Contains(err.Error(), "as JSON")
    if corrupted {
        // delete/regenerate meta and retry
    }
    return err
}

Prevention

When it happens

Trigger: Calling shipper.ReadMetaFile (directly or via Sync, AreAllBlocksUploaded, UploadedBlocks) when the meta.json file at `path` contains malformed JSON, empty bytes, or a structurally incompatible JSON document.

Common situations: Truncated meta file after a crash/power loss mid-write; manually edited meta.json with a typo; file written by an incompatible older/newer format; filesystem corruption; reading a directory or lock file by mistake instead of the meta file.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/06027571ba2d8ab4. Report an issue: GitHub.

Appendix: source

Thrown at pkg/shipper/shipper.go:658

	if err := f.Sync(); err != nil {
		return err
	}
	if err := f.Close(); err != nil {
		return err
	}
	return renameFile(logger, tmp, path)
}

// ReadMetaFile reads the given meta from <dir>/thanos.shipper.json.
func ReadMetaFile(path string) (*Meta, error) {
	b, err := os.ReadFile(path)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to read %s", path)
	}

	var m Meta
	if err := json.Unmarshal(b, &m); err != nil {
		return nil, errors.Wrapf(err, "failed to parse %s as JSON: %q", path, string(b))
	}
	if m.Version != MetaVersion1 {
		return nil, errors.Errorf("unexpected meta file version %d", m.Version)
	}

	return &m, nil
}

func renameFile(logger log.Logger, from, to string) error {
	if err := os.RemoveAll(to); err != nil {
		return err
	}
	if err := os.Rename(from, to); err != nil {
		return err
	}

	// Directory was renamed; sync parent dir to persist rename.
	pdir, err := fileutil.OpenDir(filepath.Dir(to))

View on GitHub (pinned to 35b8b99117)