hashicorp/nomad · error

cannot serialize %s

Error message

cannot serialize %s

What it means

interfaceFromCtyValue ends with a default branch for cty types it does not know how to convert to plain Go values (non-primitive, non-collection, non-object/tuple, non-capsule-extractable). The comment says it should never happen; hitting it means the type/conformance contract between decodeInterface and the value was violated or a new cty kind appeared.

Source

Thrown at jobspec2/parse_map.go:175

	case t.IsObjectType():
		result := map[string]any{}

		for k := range t.AttributeTypes() {
			av := val.GetAttr(k)
			avv, err := interfaceFromCtyValue(av)
			if err != nil {
				return nil, err
			}

			result[k] = avv
		}
		return result, nil
	case t.IsCapsuleType():
		rawVal := val.EncapsulatedValue()
		return rawVal, nil
	default:
		// should never happen
		return nil, fmt.Errorf("cannot serialize %s", t.FriendlyName())
	}
}

func isCollectionOfMaps(t cty.Type) bool {
	switch {
	case t.IsCollectionType():
		et := t.ElementType()
		return et.IsMapType() || et.IsObjectType()
	case t.IsTupleType():
		ets := t.TupleElementTypes()
		for _, et := range ets {
			if !et.IsMapType() && !et.IsObjectType() {
				return false
			}
		}

		return len(ets) > 0
	default:

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Report/inspect the type name in the message; confirm the jobspec value's declared type matches the supplied value.
  2. Upgrade (or pin) the hashicorp/hcl2/cty dependency so type kinds and conversion code agree.
  3. Simplify the jobspec construct producing the exotic type (avoid unusual nested/type expressions).
  4. If reproducible, file a bug — this code path is documented as unreachable under correct preconditions.

Example fix

// before
// val declared as cty.DynamicPseudoType but carries unhandled kind

// after
// declare explicit concrete types in the jobspec
variable "port" { type = number }
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-check convertibility
typeName := t.FriendlyName()
switch {
case t.IsPrimitiveType(), t.IsCollectionType(), t.IsObjectType(), t.IsTupleType(), t.IsCapsuleType():
    // handled
default:
    return fmt.Errorf("unsupported cty type for decoding: %s", typeName)
}

Type guard

func isSupportedCtyType(t cty.Type) bool {
    return t.IsPrimitiveType() || t.IsCollectionType() ||
        t.IsObjectType() || t.IsTupleType() || t.IsCapsuleType()
}

Try / catch

v, err := interfaceFromCtyValue(val, t)
if err != nil && strings.HasPrefix(err.Error(), "cannot serialize ") {
    // capture type name, check dependency versions, report bug
}

Prevention

When it happens

Trigger: decodeInterface invoked with a cty.Type that matches none of the handled switch cases and whose IsCapsuleType branch does not apply, causing 'cannot serialize <FriendlyName>'.

Common situations: Bug in the library or an upgraded cty version introducing a type kind jobspec2 does not handle; decoding a value whose declared type does not match its runtime conformance (violated precondition); exotic capsule types from extensions.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/2ae177227ad3a64d. Report an issue: GitHub.