cayleygraph/cayley · error

must execute a Step

Error message

must execute a Step

What it means

linkedql.Execute takes a deserialized JSON-LD query document, converts it, and requires the result to implement the linkedql.Step interface before it can build an iterator. If the decoded item is not a Step (e.g. it is a plain document, a Document/Query wrapper, or an unknown/misspelled @type), the type assertion fails and this error is returned. It signals that the value passed to Execute is not an executable query step.

Source

Thrown at query/linkedql/linkedql.go:56

}

// NewSession creates a new Session.
func NewSession(qs graph.QuadStore) *Session {
	return &Session{
		qs: qs,
	}
}

// Execute for a given context, query and options return an iterator of results.
func (s *Session) Execute(ctx context.Context, query string, opt query.Options) (query.Iterator, error) {
	item, err := Unmarshal([]byte(query))
	if err != nil {
		return nil, err
	}
	ns := voc.Namespaces{}
	step, ok := item.(Step)
	if !ok {
		return nil, errors.New("must execute a Step")
	}
	return BuildIterator(step, s.qs, &ns)
}

// BuildIterator for given Step returns a query.Iterator
func BuildIterator(step Step, qs graph.QuadStore, ns *voc.Namespaces) (query.Iterator, error) {
	switch s := step.(type) {
	case IteratorStep:
		return s.BuildIterator(qs, ns)
	case PathStep:
		return NewValueIteratorFromPathStep(s, qs, ns)
	}
	return nil, errors.New("must execute a IteratorStep or PathStep")
}

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Parse the query document with linkedql.FromJSON (or the step builders) so the value is a Step before calling Execute.
  2. Verify the @type in the JSON-LD document matches a registered linkedql step name.
  3. If passing code-built queries, use constructors like linkedql.NewVertex, linkedql.Out, etc., instead of raw structs/maps.
  4. Check your linkedql/vocabulary version matches the documents you are loading (renamed or removed step types).

Example fix

// before
var doc map[string]interface{}
json.Unmarshal(data, &doc)
it, err := linkedql.Execute(ctx, qs, doc)
// after
step, err := linkedql.FromJSON(data)
if err != nil { return err }
it, err := linkedql.Execute(ctx, qs, step)
Defensive patterns

Strategy: type-guard

Validate before calling

step, err := linkedql.FromJSON(data)
if err != nil {
    return fmt.Errorf("query document is not a valid linkedql step: %w", err)
}

Type guard

if _, ok := item.(linkedql.Step); !ok {
    return fmt.Errorf("item of type %T is not a linkedql.Step; parse with linkedql.FromJSON first", item)
}

Try / catch

it, err := linkedql.Execute(ctx, qs, step)
if err != nil {
    if err.Error() == "must execute a Step" {
        return fmt.Errorf("query document @type %q is not a registered step: %w", docType, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling linkedql.Execute(ctx, qs, item) where item, after FromJSON/decoding, is not a Step — e.g. passing a raw map[string]interface{} document instead of the parsed step, a query document whose @type is not a registered step, or the output of a wrapper type rather than a step.

Common situations: Loading JSON-LD query files with an unregistered or misspelled @type; passing the top-level query envelope instead of the contained step to Execute; version drift where a step type was renamed or removed so it no longer deserializes to a Step; hand-constructing query objects without going through the step builders.

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/b3070d2d909d497c. Report an issue: GitHub.