cayleygraph/cayley · error

couldn't decode value: %v

Error message

couldn't decode value: %v

What it means

After successfully obtaining the raw bytes of a protobuf value, toQuadValue runs proto.Unmarshal into pquads.Value; this error wraps any unmarshal failure. The bytes exist but are not a valid pquads.Value message — the stored blob is malformed, truncated, or encoded by an incompatible proto schema.

Source

Thrown at graph/nosql/quadstore.go:544

	}
	var err error
	// prefer protobuf representation
	if v, ok := d[fldValPb]; ok {
		var b []byte
		switch v := v.(type) {
		case nosql.String:
			b, err = base64.StdEncoding.DecodeString(string(v))
		case nosql.Bytes:
			b = []byte(v)
		default:
			err = fmt.Errorf("unexpected type for pb field: %T", v)
		}
		if err != nil {
			return nil, err
		}
		var p pquads.Value
		if err := proto.Unmarshal(b, &p); err != nil {
			return nil, fmt.Errorf("couldn't decode value: %v", err)
		}
		return p.ToNative(), nil
	} else if v, ok := d[fldValInt]; ok {
		if opt.Number32 {
			// parse from string, so we are confident that we will get exactly the same value
			if vs, ok := d[fldValStrInt].(nosql.String); ok {
				iv := quad.Int(stoi(string(vs)))
				return iv, nil
			}
		}
		vi, err := asInt(v)
		if err != nil {
			return nil, err
		}
		return quad.Int(vi), nil
	} else if v, ok := d[fldValFloat]; ok {
		var vf quad.Float
		switch v := v.(type) {

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Identify the affected documents and delete/rewrite their value fields with a fresh proto.Marshal(pquads.Value).
  2. Dump and re-import the store to regenerate all protobuf value blobs.
  3. Confirm the pquads proto schema version matches the Cayley version reading the data.
  4. If the error is transient storage corruption, restore from backup or re-run the import that wrote the values.

Example fix

// before
if err := proto.Unmarshal(b, &p); err != nil {
    return nil, fmt.Errorf("couldn't decode value: %v", err)
}
// after
// writer side: ensure valid encoding
raw, err := proto.Marshal(&pquads.Value{...})
if err != nil { return err }
doc[fldValPB] = nosql.Bytes(raw)
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity check blob non-empty before unmarshal
if len(b) == 0 {
    return nil, errors.New("empty pb value blob")
}

Try / catch

val, err := toQuadValue(opt, doc)
if err != nil && strings.HasPrefix(err.Error(), "couldn't decode value") {
    log.Printf("corrupt protobuf value, dropping doc: %v", err)
    return quad.Raw(""), nil
}

Prevention

When it happens

Trigger: Reading a fldValPB field whose bytes were corrupted (partial write), hand-edited, or written with a different protobuf schema/version so Unmarshal fails.

Common situations: Interrupted bulk import leaving truncated value blobs; schema drift between Cayley versions of pquads.Value; custom tooling writing wrong bytes into the pb field.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/3351c3dc75457ea3. Report an issue: GitHub.