cayleygraph/cayley · error

cannot scan %T to NodeHash

Error message

cannot scan %T to NodeHash

What it means

NodeHash.Scan implements sql.Scanner; it requires the driver to deliver the hash as a []byte. If the database/driver returns any other Go type (string, int64, etc.), Scan returns "cannot scan %T to NodeHash". This is a type mismatch between driver output and the expected binary hash column.

Source

Thrown at graph/sql/quadstore.go:85

type NodeHash struct {
	refs.ValueHash
}

func (h NodeHash) SQLValue() interface{} {
	if !h.Valid() {
		return nil
	}
	return []byte(h.ValueHash[:])
}
func (h *NodeHash) Scan(src interface{}) error {
	if src == nil {
		*h = NodeHash{}
		return nil
	}
	b, ok := src.([]byte)
	if !ok {
		return fmt.Errorf("cannot scan %T to NodeHash", src)
	}
	if len(b) == 0 {
		*h = NodeHash{}
		return nil
	} else if len(b) != quad.HashSize {
		return fmt.Errorf("unexpected hash length: %d", len(b))
	}
	copy(h.ValueHash[:], b)
	return nil
}

func HashOf(s quad.Value) NodeHash {
	return NodeHash{refs.HashOf(s)}
}

type QuadHashes struct {
	refs.QuadHash
}

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Store/alias hash columns as binary types (BLOB/BINARY/BYTEA) so the driver returns []byte.
  2. Check driver settings that force text/return protocol and switch to binary parameters.
  3. Scan into a string or sql.RawBytes first and convert to NodeHash via HashOf/decoding yourself.
  4. Ensure the schema was created by the store's own Init so column types match.

Example fix

// before
var h NodeHash
rows.Scan(&h) // driver returns string
// after
var s string
rows.Scan(&s)
h := HashOf(quad.Raw(s))
Defensive patterns

Strategy: validation

Validate before calling

// ensure hash columns are binary so the driver returns []byte
// check schema: information_schema.columns WHERE data_type IN ('blob','binary','bytea')

Try / catch

var h NodeHash
if err := rows.Scan(&h); err != nil {
    if strings.HasPrefix(err.Error(), "cannot scan") {
        // scan into string/raw bytes and convert manually
    }
}

Prevention

When it happens

Trigger: Calling rows.Scan (via QuadStore.Scan / iterator scanning) into NodeHash when the column is not stored as binary/BLOB, so the driver returns e.g. string or []uint8-adjacent non-byte types.

Common situations: Schema where hash columns are TEXT/VARCHAR instead of BLOB/BINARY; drivers that decode hex hashes into strings (different MySQL driver, Postgres text mode); using a driver whose value conversion differs.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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