{"record":{"id":"0f622b681f2d996f","repo":"cayleygraph/cayley","slug":"blank-node-id-must-start-with","errorCode":null,"errorMessage":"blank node ID must start with \"_:\"","messagePattern":"blank node ID must start with \"_:\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/linkedql/registry.go","lineNumber":245,"sourceCode":"}\n\nfunc normalizeQuery(data []byte) ([]byte, error) {\n\tvar query interface{}\n\tjson.Unmarshal(data, &query)\n\tprocessor := ld.NewJsonLdProcessor()\n\topts := ld.NewJsonLdOptions(\"\")\n\tcompact, err := processor.Compact(query, nil, opts)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn json.Marshal(compact)\n}\n\nfunc parseBNode(s string) (quad.BNode, error) {\n\tif !strings.HasPrefix(s, \"_:\") {\n\t\treturn \"\", fmt.Errorf(\"blank node ID must start with \\\"_:\\\"\")\n\t}\n\treturn quad.BNode(s[2:]), nil\n}\n\nfunc parseIRI(s string) (quad.IRI, error) {\n\treturn quad.IRI(s), nil\n}\n\nfunc parseIdentifier(s string) (quad.Value, error) {\n\tbnode, err := parseBNode(s)\n\tif err == nil {\n\t\treturn bnode, nil\n\t}\n\tiri, err := parseIRI(s)\n\tif err == nil {\n\t\treturn iri, nil\n\t}\n\treturn nil, fmt.Errorf(\"can not parse JSON-LD identifier: %#v\", s)","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/linkedql/registry.go#L227-L263","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Prefix the blank node label with \"_:\" before passing it, e.g. \"_:b0\" instead of \"b0\".","If the value is actually a resource, use a full absolute IRI (e.g. \"http://example.com/b0\") so parseIRI handles it instead.","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."],"exampleFix":"// before\n{\"@id\": \"b0\"}\n// after\n{\"@id\": \"_:b0\"}","handlingStrategy":"validation","validationCode":"func isValidBNode(s string) bool { return strings.HasPrefix(s, \"_:\") && len(s) > 2 }\n// before building a step: if !isValidBNode(id) { id = \"_:\" + id }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize all blank node labels with a \"_:\" prefix helper at document-load time.","Prefer absolute IRIs unless a blank node is genuinely intended.","Unit-test step documents against the JSON-LD blank node syntax rules."],"tags":["go","json-ld","rdf","blank-node","identifier"],"backgroundTag":"invalid-identifier-format","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}