cayleygraph/cayley · error

must specify a tag name when saving a path

Error message

must specify a tag name when saving a path

What it means

In the Gizmo (Gremlin-like) query language, Save(via) stores the reached value under a tag. When the "via" argument is a path object (a subquery) rather than a plain value, the tag name becomes mandatory because it can no longer be inferred from a literal predicate/vertex string. If the tag string is empty in that case, the VM aborts with this error.

Source

Thrown at query/gizmo/traversals.go:468

}
func (p *pathObject) save(call goja.FunctionCall, rev, opt bool) goja.Value {
	args := exportArgs(call.Arguments)
	if len(args) > 2 || len(args) == 0 {
		return throwErr(p.s.vm, errArgCount{Got: len(args)})
	}
	var vtag interface{} = ""
	if len(args) == 2 {
		vtag = args[1]
	}
	tag, ok := vtag.(string)
	if !ok {
		return throwErr(p.s.vm, fmt.Errorf("expected string, got: %T", vtag))
	}
	via := args[0]
	if vp, ok := via.(*pathObject); ok {
		via = vp.path
		if tag == "" {
			return throwErr(p.s.vm, errors.New("must specify a tag name when saving a path"))
		}
	} else {
		qv, err := toQuadValue(via)
		via = qv
		if err != nil {
			return throwErr(p.s.vm, err)
		}
		if tag == "" {
			if p.s.col == query.JSONLD {
				switch qv := qv.(type) {
				case quad.IRI:
					tag = string(qv)
				case quad.String:
					tag = string(qv)
				default:
					tag = quad.StringOf(qv)
				}
			} else {

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Provide a non-empty tag string as the second argument: g.Save(g.V("foo").Out(), "myTag").
  2. If you meant to save a literal predicate value, pass the string directly (tag can stay implicit for string via): g.Save("pred", "tag").
  3. Review SaveR/SaveOpt/SaveOptR call sites for an empty-string tag when via is a path.
  4. Validate tag names when generating Gizmo queries from templates or code.

Example fix

// before
it := g.Save(g.V("status").Out("followers"), "")
// after
it := g.Save(g.V("status").Out("followers"), "followersTag")
Defensive patterns

Strategy: validation

Validate before calling

function savePath(pathObj, tag) {
  if (pathObj instanceof g.Path && (!tag || typeof tag !== "string")) {
    throw new Error("Save with a path via requires a non-empty tag string");
  }
  return g.Save(pathObj, tag);
}

Type guard

function isPathObject(v) { return v != null && typeof v === "object" && typeof v.ToArray === "function"; }
// if isPathObject(via) and tag === "" -> Save will fail; require a tag

Try / catch

try {
  result = g.Save(via, tag).Iterate();
} catch (e) {
  if (e.message.includes("must specify a tag name")) {
    throw new Error("Save(path, tag) requires a non-empty tag; supply one for via=" + via);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling g.Save(<pathObject>, "") or SaveR/SaveOpt/SaveOptR with a path as the via argument and an empty tag string. E.g. g.Save(g.V("foo").Out(), "") — a path via with no tag.

Common situations: Copy-pasting Save calls where the first form used a string predicate (tag optional) and later swapping in a path; building queries programmatically and leaving the tag empty; misunderstanding that a tag is optional only when via is a literal value.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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