{"record":{"id":"049efaf83454d2ed","repo":"apache/beam","slug":"substituting-type-v-type-not-bound","errorCode":null,"errorMessage":"substituting type %v: type not bound","messagePattern":"substituting type (.+?): type not bound","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/typex/fulltype.go","lineNumber":416,"sourceCode":"func Substitute(list []FullType, m map[string]reflect.Type) ([]FullType, error) {\n\tvar ret []FullType\n\tfor _, t := range list {\n\t\trepl, err := substitute(t, m)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tret = append(ret, repl)\n\t}\n\treturn ret, nil\n}\n\nfunc substitute(t FullType, m map[string]reflect.Type) (FullType, error) {\n\tswitch t.Class() {\n\tcase Universal:\n\t\tname := t.Type().Name()\n\t\trepl, ok := m[name]\n\t\tif !ok {\n\t\t\treturn nil, errors.Errorf(\"substituting type %v: type not bound\", name)\n\t\t}\n\t\treturn New(repl), nil\n\tcase Container:\n\t\tcomp, err := substituteList(t.Components(), m)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif IsList(t.Type()) {\n\t\t\treturn New(reflect.SliceOf(comp[0].Type()), comp...), nil\n\t\t}\n\t\treturn nil, errors.Errorf(\"unexpected aggregate %v, only slices allowed\", t)\n\tcase Composite:\n\t\tcomp, err := substituteList(t.Components(), m)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn New(t.Type(), comp...), nil\n","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/typex/fulltype.go#L398-L434","documentation":"typex.Substitute replaces every universal (variable) type in a FullType using the binding map produced by Bind. If a type variable's name is absent from the map, substitution cannot proceed and this error is returned.","triggerScenarios":"Calling typex.Substitute(t, m) where t contains a Universal type whose Name() has no key in m — usually because Bind was never run on a type containing that variable, or the map came from a Bind over a different model set.","commonSituations":"Users hand-construct substitution maps (map[string]reflect.Type) with a typo in the variable name (e.g. \"x\" vs \"T\"); or reuse a Bind result across FullTypes that reference additional variables; seen when building custom coders or graph rewriting in Beam Go.","solutions":["Build the map via typex.Bind over the same models used to define the type variables, rather than hand-writing it.","Check the variable name in the message against your map keys; fix the spelling or add the missing binding.","If the type should have no free variables, verify it was constructed with concrete types, not typex.T/X placeholders.","Call SubstituteFull on a small test FullType with the same map to isolate which variable is unbound."],"exampleFix":"// before\nm := map[string]reflect.Type{\"x\": reflect.TypeOf(\"\")}\ntypex.Substitute(t, m) // variable is named \"T\"\n\n// after\nm := map[string]reflect.Type{\"T\": reflect.TypeOf(\"\")}\ntypex.Substitute(t, m)","handlingStrategy":"validation","validationCode":"func allBound(t typex.FullType, m map[string]reflect.Type) bool {\n    switch t.Class() {\n    case typex.Universal:\n        _, ok := m[t.Type().Name()]\n        return ok\n    default:\n        for _, c := range t.Components() {\n            if !allBound(c, m) {\n                return false\n            }\n        }\n        return true\n    }\n}","typeGuard":"func isFullyConcrete(t typex.FullType) bool {\n    if t.Class() == typex.Universal {\n        return false\n    }\n    for _, c := range t.Components() {\n        if !isFullyConcrete(c) {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"out, err := typex.Substitute(t, m)\nif err != nil {\n    return fmt.Errorf(\"substitution: %w (check map keys against variable names)\", err)\n}","preventionTips":["Derive the substitution map from typex.Bind instead of hand-writing map literals.","Copy variable names from the same typex.T/typex.X constants used to build the model, never retype them.","Before substituting, assert the FullType's free variables all exist in the map.","Reuse one shared Bind result across all types derived from the same model set."],"tags":["go","apache-beam","type-substitution"],"backgroundTag":"record-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}