{"record":{"id":"4f78cd6f08df2cea","repo":"cayleygraph/cayley","slug":"node-tokens-not-valid","errorCode":null,"errorMessage":"node tokens not valid","messagePattern":"node tokens not valid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graph/gaedatastore/quadstore.go","lineNumber":561,"sourceCode":"\terr := datastore.Get(qs.context, key, n)\n\tif err != nil && err != datastore.ErrNoSuchEntity {\n\t\treturn refs.Size{}, err\n\t}\n\treturn refs.Size{Value: n.Size, Exact: true}, nil\n}\n\nfunc (qs *QuadStore) Close() error {\n\tqs.context = nil\n\treturn nil\n}\n\nfunc (qs *QuadStore) QuadDirection(val graph.Ref, dir quad.Direction) (graph.Ref, error) {\n\tt, ok := val.(*Token)\n\tif !ok {\n\t\treturn nil, errors.New(\"token not valid\")\n\t}\n\tif t.Kind == nodeKind {\n\t\treturn nil, errors.New(\"node tokens not valid\")\n\t}\n\tvar offset int\n\tswitch dir {\n\tcase quad.Subject:\n\t\toffset = 0\n\tcase quad.Predicate:\n\t\toffset = (quad.HashSize * 2)\n\tcase quad.Object:\n\t\toffset = (quad.HashSize * 2) * 2\n\tcase quad.Label:\n\t\toffset = (quad.HashSize * 2) * 3\n\t}\n\tsub := t.Hash[offset : offset+(quad.HashSize*2)]\n\treturn &Token{Kind: nodeKind, Hash: sub}, nil\n}\n","sourceCodeStart":543,"sourceCodeEnd":577,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/graph/gaedatastore/quadstore.go#L543-L577","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the token Kind before calling: only invoke QuadDirection when tok.Kind != nodeKind.","For node tokens there is nothing to resolve; handle them separately (e.g. return the node itself or skip).","Refactor the caller to track whether a ref came from a quad result or a value result."],"exampleFix":"// before\nref, err := qs.QuadDirection(tok, quad.Subject)\n// after\nif tok.(*gaedatastore.Token).Kind == gaedatastore.NodeKind {\n    return nil, nil // node token: no direction to resolve\n}\nref, err := qs.QuadDirection(tok, quad.Subject)","handlingStrategy":"type-guard","validationCode":"if t, ok := ref.(*gaedatastore.Token); ok && t.Kind == gaedatastore.NodeKind {\n    return nil // node token: nothing to resolve\n}","typeGuard":"func isNodeToken(ref graph.Ref) bool {\n    t, ok := ref.(*gaedatastore.Token)\n    return ok && t.Kind == gaedatastore.NodeKind\n}","tryCatchPattern":"ref, err := qs.QuadDirection(val, dir)\nif err != nil && err.Error() == \"node tokens not valid\" {\n    return val, nil // it's a node: return as-is\n}","preventionTips":["Check token Kind before resolving directions.","Separate handling for node results vs quad results in iteration code.","Document that QuadDirection is quad-token-only."],"tags":["go","graph","invalid-argument-value"],"backgroundTag":"invalid-argument-value","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}