{"record":{"id":"4607a68461f34cf3","repo":"gohugoio/hugo","slug":"s-is-an-unexported-method-of-type-s","errorCode":null,"errorMessage":"%s is an unexported method of type %s","messagePattern":"(.+?) is an unexported method of type (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/where.go","lineNumber":341,"sourceCode":"\tobjPtr := obj\n\tif !hreflect.IsInterfaceOrPointer(objPtr.Kind()) && objPtr.CanAddr() {\n\t\tobjPtr = objPtr.Addr()\n\t}\n\n\tmt := hreflect.GetMethodByNameForType(objPtr.Type(), elemName)\n\tif mt.Func.IsValid() {\n\t\t// Receiver is the first argument.\n\t\targs := []reflect.Value{objPtr}\n\t\tnum := mt.Type.NumIn()\n\t\tmaxNumIn := 1\n\t\tif num > 1 && hreflect.IsContextType(mt.Type.In(1)) {\n\t\t\targs = append(args, ctx)\n\t\t\tmaxNumIn = 2\n\t\t}\n\n\t\tswitch {\n\t\tcase mt.PkgPath != \"\":\n\t\t\treturn zero, fmt.Errorf(\"%s is an unexported method of type %s\", elemName, typ)\n\t\tcase mt.Type.NumIn() > maxNumIn:\n\t\t\treturn zero, fmt.Errorf(\"%s is a method of type %s but requires more than %d parameter\", elemName, typ, maxNumIn)\n\t\tcase mt.Type.NumOut() == 0:\n\t\t\treturn zero, fmt.Errorf(\"%s is a method of type %s but returns no output\", elemName, typ)\n\t\tcase mt.Type.NumOut() > 2:\n\t\t\treturn zero, fmt.Errorf(\"%s is a method of type %s but returns more than 2 outputs\", elemName, typ)\n\t\tcase mt.Type.NumOut() == 1 && mt.Type.Out(0).Implements(errorType):\n\t\t\treturn zero, fmt.Errorf(\"%s is a method of type %s but only returns an error type\", elemName, typ)\n\t\tcase mt.Type.NumOut() == 2 && !mt.Type.Out(1).Implements(errorType):\n\t\t\treturn zero, fmt.Errorf(\"%s is a method of type %s returning two values but the second value is not an error type\", elemName, typ)\n\t\t}\n\t\tres := mt.Func.Call(args)\n\t\tif len(res) == 2 && !res[1].IsNil() {\n\t\t\treturn zero, fmt.Errorf(\"error at calling a method %s of type %s: %s\", elemName, typ, res[1].Interface().(error))\n\t\t}\n\t\treturn res[0], nil\n\t}\n","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/where.go#L323-L359","documentation":"Thrown by Hugo's `where` template function while resolving the key against each element. `evaluateSubElem` (tpl/collections/where.go:328-341) first looks up a method by name; if it finds one but the method's reflect PkgPath is non-empty (i.e. its first letter is lowercase / unexported), it refuses to call it. Go's reflect package cannot invoke unexported methods, so Hugo surfaces the name and type so you can correct the template key.","triggerScenarios":"Calling `{{ where $items \"privateHelper\" \"==\" x }}` where the element type has a method `func (t) privateHelper() ...` (lowercase). Also reachable via a dotted key path like `.foo.privateHelper` where a path segment names an unexported method.","commonSituations":"Template author guesses a method name by guessing lowercase Go conventions; an embedded/internal type exposes only a private helper that the public API wraps; refactoring renames a method to lowercase.","solutions":["Use the exported (capitalized) method name as the where key, e.g. `CountItems` instead of `countItems`.","If no exported equivalent exists, add a thin exported accessor method on the element type.","Verify the method name against the type with `reflect.TypeFor[T]().Method(i).Name` or the package docs."],"exampleFix":"// before\n{{ where $items \"countItems\" \"==\" 3 }}\n// after\n{{ where $items \"CountItems\" \"==\" 3 }}","handlingStrategy":"validation","validationCode":"{{/* Verify the name resolves to an exported method before filtering */}}\n{{ $t := reflect.TypeOf (index $items 0) }}\n{{ $ok := false }}\n{{ range $i := seq (len $t.NumMethod false) }}\n  {{ $m := $t.Method $i }}\n  {{ if eq $m.Name $key }}{{ $ok = true }}{{ end }}\n{{ end }}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only reference exported (capitalized) methods in `where` keys.","Keep a list of template-visible exported method names in your model docs.","After renaming a method, grep templates for the old lowercase spelling."],"tags":["hugo","go-templates","where","reflection","unexported"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}