owasp-amass/amass · error

failed to cast the DomainRecord

Error message

failed to cast the DomainRecord

What it means

getRegisteredDomainEntity expects record.Asset to hold an *oamreg.DomainRecord so it can look up the registered domain entity in the graph database. When the asset stored on the Entity is any other type, the Go type assertion fails and this sentinel error is returned. It indicates the caller passed an entity whose asset is not a DomainRecord (e.g. an FQDN, IPAddress, or other asset kind) to a DomainRecord-only code path.

Source

Thrown at engine/plugins/horizontals/plugin.go:481

			if a, conf := sess.Scope().IsAssetInScope(ent.Asset, econf); conf >= econf {
				if strings.EqualFold(a.Key(), ent.Asset.Key()) {
					_ = sess.Backlog().Enqueue(ent)
				}
			}
		}
	}
}

func (h *horizPlugin) enqueueIfOutOfScope(sess et.Session, ent *dbt.Entity) {
	if !h.isEntityInScope(sess, ent) {
		h.addToScopeAndEnqueue(sess, ent)
	}
}

func (h *horizPlugin) getRegisteredDomainEntity(sess et.Session, record *dbt.Entity) (*dbt.Entity, error) {
	dr, valid := record.Asset.(*oamreg.DomainRecord)
	if !valid {
		return nil, errors.New("failed to cast the DomainRecord")
	}

	ctx, cancel := context.WithTimeout(sess.Ctx(), 30*time.Second)
	defer cancel()

	if ents, err := sess.DB().FindEntitiesByContent(ctx, oam.FQDN, time.Time{}, 1, dbt.ContentFilters{
		"name": dr.Domain,
	}); err == nil && len(ents) == 1 {
		return ents[0], nil
	}

	return nil, fmt.Errorf("failed to obtain the registered domain name FQDN for: %s", dr.Domain)
}

func (h *horizPlugin) getRegisteredNetblockEntity(sess et.Session, record *dbt.Entity) (*dbt.Entity, error) {
	iprec, valid := record.Asset.(*oamreg.IPNetRecord)
	if !valid {
		return nil, errors.New("failed to cast the IPNetRecord")

View on GitHub (pinned to 79299dce87)

Solutions

  1. Before calling getRegisteredDomainEntity, assert record.Asset.(*oamreg.DomainRecord) and skip/return nil if it fails
  2. Check the upstream producer: ensure the event chain only routes *oamreg.DomainRecord assets into processInScope/processDomainRecord
  3. If entities come from DB queries, verify the asset reconstruction maps content of type oam.DomainRecord back to *oamreg.DomainRecord

Example fix

// before
ents, err := h.getRegisteredDomainEntity(sess, record)
if err != nil {
	return err
}

// after
if _, ok := record.Asset.(*oamreg.DomainRecord); !ok {
	return nil
}
ents, err := h.getRegisteredDomainEntity(sess, record)
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := record.Asset.(*oamreg.DomainRecord); !ok {
	return nil // not a DomainRecord; skip
}

Type guard

func isDomainRecord(a interface{}) (*oamreg.DomainRecord, bool) {
	dr, ok := a.(*oamreg.DomainRecord)
	return dr, ok
}

Try / catch

if err != nil {
	var castErr *assertErr
	if errors.As(err, &castErr) {
		return nil // skip wrong-type entities
	}
	return err
}

Prevention

When it happens

Trigger: processInScope or processDomainRecord passes an entity whose Asset field is not *oamreg.DomainRecord into getRegisteredDomainEntity — e.g. an event tagged as a domain-related relation carries a different asset type, or a DB query returns entities whose Asset was not reconstructed as DomainRecord.

Common situations: Adding a new event/relation type that routes into the horizontals plugin without updating its asset dispatch; database reload where entity assets deserialize to a generic type; plugins emitting records with the wrong asset struct.

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 owasp-amass/amass@79299dce87 (2026-09-06). Data as JSON: /api/errors/2e639bdba2b5f8eb. Report an issue: GitHub.