cayleygraph/cayley · error

blank node ID must start with "_:"

Error message

blank node ID must start with "_:"

What it means

parseBNode converts a JSON-LD string into a quad.BNode, but blank nodes in JSON-LD are only valid when serialized with the "_:" prefix. If the input string lacks that prefix the function refuses to interpret it as a blank node and returns this error. The library enforces the RDF/JSON-LD convention that blank node identifiers are lexically distinguished from IRIs.

Source

Thrown at query/linkedql/registry.go:245

}

func normalizeQuery(data []byte) ([]byte, error) {
	var query interface{}
	json.Unmarshal(data, &query)
	processor := ld.NewJsonLdProcessor()
	opts := ld.NewJsonLdOptions("")
	compact, err := processor.Compact(query, nil, opts)

	if err != nil {
		return nil, err
	}

	return json.Marshal(compact)
}

func parseBNode(s string) (quad.BNode, error) {
	if !strings.HasPrefix(s, "_:") {
		return "", fmt.Errorf("blank node ID must start with \"_:\"")
	}
	return quad.BNode(s[2:]), nil
}

func parseIRI(s string) (quad.IRI, error) {
	return quad.IRI(s), nil
}

func parseIdentifier(s string) (quad.Value, error) {
	bnode, err := parseBNode(s)
	if err == nil {
		return bnode, nil
	}
	iri, err := parseIRI(s)
	if err == nil {
		return iri, nil
	}
	return nil, fmt.Errorf("can not parse JSON-LD identifier: %#v", s)

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Prefix the blank node label with "_:" before passing it, e.g. "_:b0" instead of "b0".
  2. If the value is actually a resource, use a full absolute IRI (e.g. "http://example.com/b0") so parseIRI handles it instead.
  3. If the node should be auto-generated, omit the identifier and let the library mint a fresh blank node rather than supplying a bare label.

Example fix

// before
{"@id": "b0"}
// after
{"@id": "_:b0"}
Defensive patterns

Strategy: validation

Validate before calling

func isValidBNode(s string) bool { return strings.HasPrefix(s, "_:") && len(s) > 2 }
// before building a step: if !isValidBNode(id) { id = "_:" + id }

Prevention

When it happens

Trigger: Calling code paths that reach parseBNode (via parseIdentifier during BuildIdentifier or parseValue) with a plain string like "b0" or "node1" instead of "_:b0". This happens when a step's @id value uses a bare label that is not a valid absolute IRI, so parseIRI input falls through or the value is dispatched to blank-node parsing.

Common situations: Hand-written JSON-LD step documents where authors omit the "_:" prefix for blank node references; data produced by tools that output bare internal node labels; copy-pasted node IDs from database exports that strip the prefix.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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