cayleygraph/cayley · error

node tokens not valid

Error message

node tokens not valid

What it means

QuadDirection can only resolve directions on quad tokens (which encode a quad and an offset). A token of Kind nodeKind represents a standalone node value, which has no containing quad and thus no direction to read; passing such a token is rejected with this error.

Source

Thrown at graph/gaedatastore/quadstore.go:561

	err := datastore.Get(qs.context, key, n)
	if err != nil && err != datastore.ErrNoSuchEntity {
		return refs.Size{}, err
	}
	return refs.Size{Value: n.Size, Exact: true}, nil
}

func (qs *QuadStore) Close() error {
	qs.context = nil
	return nil
}

func (qs *QuadStore) QuadDirection(val graph.Ref, dir quad.Direction) (graph.Ref, error) {
	t, ok := val.(*Token)
	if !ok {
		return nil, errors.New("token not valid")
	}
	if t.Kind == nodeKind {
		return nil, errors.New("node tokens not valid")
	}
	var offset int
	switch dir {
	case quad.Subject:
		offset = 0
	case quad.Predicate:
		offset = (quad.HashSize * 2)
	case quad.Object:
		offset = (quad.HashSize * 2) * 2
	case quad.Label:
		offset = (quad.HashSize * 2) * 3
	}
	sub := t.Hash[offset : offset+(quad.HashSize*2)]
	return &Token{Kind: nodeKind, Hash: sub}, nil
}

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Check the token Kind before calling: only invoke QuadDirection when tok.Kind != nodeKind.
  2. For node tokens there is nothing to resolve; handle them separately (e.g. return the node itself or skip).
  3. Refactor the caller to track whether a ref came from a quad result or a value result.

Example fix

// before
ref, err := qs.QuadDirection(tok, quad.Subject)
// after
if tok.(*gaedatastore.Token).Kind == gaedatastore.NodeKind {
    return nil, nil // node token: no direction to resolve
}
ref, err := qs.QuadDirection(tok, quad.Subject)
Defensive patterns

Strategy: type-guard

Validate before calling

if t, ok := ref.(*gaedatastore.Token); ok && t.Kind == gaedatastore.NodeKind {
    return nil // node token: nothing to resolve
}

Type guard

func isNodeToken(ref graph.Ref) bool {
    t, ok := ref.(*gaedatastore.Token)
    return ok && t.Kind == gaedatastore.NodeKind
}

Try / catch

ref, err := qs.QuadDirection(val, dir)
if err != nil && err.Error() == "node tokens not valid" {
    return val, nil // it's a node: return as-is
}

Prevention

When it happens

Trigger: Calling QuadDirection(val, dir) where val is a *Token whose Kind equals nodeKind — i.e. a node token obtained for a standalone value (e.g. from NameOf/value lookups) rather than a quad-side token.

Common situations: Iterating results that contain both node and quad refs and blindly calling QuadDirection on all of them; confusing node tokens (produced by QuadStore.ValueOfNode equivalents) with quad tokens.

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 cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/4f78cd6f08df2cea. Report an issue: GitHub.