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), nil

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Wrap the identifier string in a node object: {"@id": "<value>"} before passing it where a node object is expected.
  2. Check the enclosing step field's expected shape in the LinkedQL registry docs — some fields take strings, others require {"@id": ...}.
  3. 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

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


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