cayleygraph/cayley · error
unexpected type: %T
Error message
unexpected type: %T
What it means
parseIdentifierString expects its argument to be a map[string]interface{} — a JSON-LD node object like {"@id": "..."}. When the value is any other type (string, number, bool, array, nil), the type assertion fails and this error is returned. It is the registry's way of rejecting structurally wrong input before looking up the "@id" key.
Source
Thrown at query/linkedql/registry.go:269
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)
}
func parseIdentifierString(a interface{}) (string, error) {
m, ok := a.(map[string]interface{})
if !ok {
return "", fmt.Errorf("unexpected type: %T", a)
}
id, ok := m["@id"].(string)
if !ok {
return "", fmt.Errorf("expected a @id key")
}
return id, nil
}
func parseLiteral(a interface{}) (quad.Value, error) {
switch a := a.(type) {
case string:
return quad.String(a), nil
case int64:
return quad.Int(a), nil
case float64:
i := int64(a)
if a == float64(i) {
return quad.Int(i), nilView on GitHub (pinned to 81dcd7d73e)
Solutions
- Wrap the identifier string in a node object: {"@id": "<value>"} before passing it where a node object is expected.
- Check the enclosing step field's expected shape in the LinkedQL registry docs — some fields take strings, others require {"@id": ...}.
- If using a custom decoder, decode into map[string]interface{} rather than typed structs for step documents.
Example fix
// before
parseIdentifierString("_:b0") // string, not map
// after
parseIdentifierString(map[string]interface{}{"@id": "_:b0"}) Defensive patterns
Strategy: type-guard
Validate before calling
func isNodeObject(v interface{}) bool {
_, ok := v.(map[string]interface{})
return ok
}
// wrap strings: if s, ok := v.(string); ok { v = map[string]interface{}{"@id": s} } Type guard
func asNodeObject(v interface{}) (map[string]interface{}, bool) {
m, ok := v.(map[string]interface{})
return m, ok
} Try / catch
str, err := parseIdentifierString(v)
if err != nil && strings.HasPrefix(err.Error(), "unexpected type") {
if s, ok := v.(string); ok {
return parseIdentifierString(map[string]interface{}{"@id": s})
}
return fmt.Errorf("expected JSON-LD node object, got %T", v)
} Prevention
- Decode step documents with json.Unmarshal into interface{} so node objects arrive as map[string]interface{}.
- Decide on one identifier form (string vs node object) per field and document it.
- Add a schema check for step documents before passing them to the registry.
When it happens
Trigger: parseValue receiving a raw string or scalar where a node object is required — i.e. passing {"@id": "_:b0"} fields as plain strings, or passing arrays/nil into value positions that expect node objects.
Common situations: Confusion between the two accepted identifier forms: a plain string IRI is valid for parseIdentifier but not for parseIdentifierString; developers pass a string into a slot that requires the node-object form. Also occurs after custom unmarshaling that produces structs instead of map[string]interface{}.
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
- can not parse JSON-LD identifier: %#v
- can not parse %#v as a literal
- blank node ID must start with "_:"
- expected a @id key
- cannot count iterator without a valid context
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/eaee8b8bdc9f6d7b.
Report an issue: GitHub.