cayleygraph/cayley · error

Datastore: invalid action

Error message

Datastore: invalid action

What it means

ApplyDeltas validates every delta's Action before applying it; only graph.Add and graph.Delete are supported. Any other action value causes an immediate abort of the whole batch — no partial application.

Source

Thrown at graph/gaedatastore/quadstore.go:216

		return 0, err
	}
	return len(buf), nil
}

func (w *quadWriter) Close() error {
	w.deltas = nil
	return nil
}

func (qs *QuadStore) ApplyDeltas(in []graph.Delta, ignoreOpts graph.IgnoreOpts) error {
	if qs.context == nil {
		return errors.New("No context, graph not correctly initialised")
	}
	toKeep := make([]graph.Delta, 0)
	for _, d := range in {
		if d.Action != graph.Add && d.Action != graph.Delete {
			//Defensive shortcut
			return errors.New("Datastore: invalid action")
		}
		key := qs.createKeyForQuad(d.Quad)
		keep := false
		switch d.Action {
		case graph.Add:
			found, err := qs.checkValid(key)
			if err != nil {
				return err
			}
			if found {
				if !ignoreOpts.IgnoreDup {
					return graph.ErrQuadExists
				}
			} else {
				keep = true
			}
		case graph.Delete:
			found, err := qs.checkValid(key)

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Audit delta construction and set Action explicitly to graph.Add or graph.Delete for every delta.
  2. Validate the batch before calling ApplyDeltas and reject unknown actions early.
  3. Update code that uses an action value this backend does not support; the GAE datastore backend only implements Add/Delete.
  4. Check delta-producing helpers for paths that return an empty/zero Delta.

Example fix

// before
deltas = append(deltas, graph.Delta{Quad: q})
// after
deltas = append(deltas, graph.Delta{Quad: q, Action: graph.Add})
Defensive patterns

Strategy: validation

Validate before calling

for i, d := range deltas {
    if d.Action != graph.Add && d.Action != graph.Delete {
        return fmt.Errorf("delta %d has invalid action %v", i, d.Action)
    }
}

Type guard

func validActions(ds []graph.Delta) bool {
    for _, d := range ds {
        if d.Action != graph.Add && d.Action != graph.Delete { return false }
    }
    return true
}

Try / catch

if err := qs.ApplyDeltas(deltas, ignoreOpts); err != nil {
    if strings.Contains(err.Error(), "invalid action") {
        // log offending batch, fix producer
    }
    return err
}

Prevention

When it happens

Trigger: Passing a []graph.Delta to ApplyDeltas (or the wrappers WriteQuads/AddQuadSet/ApplyTransaction) where any delta has an Action other than graph.Add or graph.Delete (e.g. zero value, graph.Update, or corrupt delta).

Common situations: Constructing deltas manually and forgetting to set Action; building a Delta with a struct literal that omits the Action field so it defaults to zero; middleware that produces custom action codes.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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