{"record":{"id":"d501388ccfc7628c","repo":"projectdiscovery/nuclei","slug":"s-is-not-a-named-struct-type","errorCode":null,"errorMessage":"%s is not a named struct type","messagePattern":"(.+?) is not a named struct type","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/devtools/tsgen/scrape.go","lineNumber":39,"sourceCode":"\t// get package\n\tpkg, ok := p.imports[pkgName]\n\tif !ok {\n\t\treturn errkit.Newf(\"package %v for type %v not found\", pkgName, typeName)\n\t}\n\t// get type\n\tobj := pkg.Types.Scope().Lookup(baseTypeName)\n\tif obj == nil {\n\t\treturn errkit.Newf(\"type %v not found in package %+v\", typeName, pkg)\n\t}\n\t// Ensure the object is a type name\n\ttypeNameObj, ok := obj.(*types.TypeName)\n\tif !ok {\n\t\treturn errkit.Newf(\"%v is not a type name\", typeName)\n\t}\n\t// Ensure the type is a named struct type\n\tnamedStruct, ok := typeNameObj.Type().Underlying().(*types.Struct)\n\tif !ok {\n\t\treturn fmt.Errorf(\"%s is not a named struct type\", typeName)\n\t}\n\t// fmt.Printf(\"got named struct %v\\n\", namedStruct)\n\t// Iterate over the struct fields\n\td := &ExtObject{\n\t\tbuiltIn: make(map[string]string),\n\t\tnested:  map[string]map[string]*ExtObject{},\n\t}\n\n\t// fmt.Printf(\"fields %v\\n\", namedStruct.NumFields())\n\tfor i := 0; i < namedStruct.NumFields(); i++ {\n\t\tfield := namedStruct.Field(i)\n\t\tfieldName := field.Name()\n\t\tif field.Exported() {\n\t\t\trecursiveScrapeType(nil, fieldName, field.Type(), d)\n\t\t}\n\t}\n\tentityMap := make(map[string]Entity)\n\t// convert ExtObject to Entity","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/devtools/tsgen/scrape.go#L21-L57","documentation":"The scraper looked up typeName in the package's scope, found it, but its Underlying() type is not *types.Struct. Scrape only supports named struct types: interfaces, maps, slices, basic types, signatures, and pointer/alias chains ending outside a struct are rejected here.","triggerScenarios":"tsgen trying to scrape a type like type FS = fs.FS (alias), type Handler interface{...}, type List []Item, or type ID string — all reachable in scope but not structs.","commonSituations":"Binding APIs that expose idiomatic Go alias/interface types; generics instantiations; standard-library types aliased into a lib's surface.","solutions":["Give the binding a concrete named struct instead: wrap the non-struct type in a struct (e.g. struct{ Items []Item })","Keep non-struct helper types out of the scraped API surface (unexport them or move them out of the module dir)","If the type genuinely must be exposed, extend the scraper to handle the kind — report an issue"],"exampleFix":"// before\ntype Permissions map[string]bool   // scraped -> error\n\n// after\ntype Permissions struct { Allow map[string]bool }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isNamedStruct(pkg *types.Package, typeName string) bool {\n    obj := pkg.Scope().Lookup(typeName)\n    if obj == nil { return false }\n    tn, ok := obj.(*types.TypeName)\n    if !ok { return false }\n    _, ok = tn.Type().Underlying().(*types.Struct)\n    return ok\n}","tryCatchPattern":"In scraper code, check the guard above before scraping and skip non-struct types with a warning; as a lib author, catch the message at codegen time and restructure the offending type into a struct.","preventionTips":["Avoid aliases to interfaces/maps/slices in scraped API surfaces","Keep binding types as plain exported structs","Extend or report the scraper when a non-struct type genuinely must be exposed"],"tags":["devtools","tsgen","go-types","code-generation"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}