{"record":{"id":"18df15a36fa700b7","repo":"GopeedLab/gopeed","slug":"execute-expects-a-string-or-function-got-t-q","errorCode":null,"errorMessage":"execute expects a string or function, got %T (%q)","messagePattern":"execute expects a string or function, got %T \\(%q\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/download/engine/webview/runtime.go","lineNumber":594,"sourceCode":"\tswitch raw := value.Export().(type) {\n\tcase string:\n\t\treturn raw, nil\n\t}\n\tobj, ok := value.(*goja.Object)\n\tif ok {\n\t\tif _, ok := goja.AssertFunction(obj); ok {\n\t\t\tsource, err := functionSource(obj)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\treturn normalizeFunctionSource(source), nil\n\t\t}\n\t}\n\tsource := strings.TrimSpace(value.String())\n\tif looksLikeFunctionSource(source) {\n\t\treturn normalizeFunctionSource(source), nil\n\t}\n\treturn \"\", fmt.Errorf(\"execute expects a string or function, got %T (%q)\", value, source)\n}\n\nfunc normalizeFunctionSource(source string) string {\n\trepaired := repairArrowObjectLiteralSource(source)\n\treturn \"(\" + repaired + \")\"\n}\n\nfunc functionSource(fn *goja.Object) (string, error) {\n\ttoStringValue := fn.Get(\"toString\")\n\ttoString, ok := goja.AssertFunction(toStringValue)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"function.toString is not callable\")\n\t}\n\tvalue, err := toString(fn)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn value.String(), nil","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/pkg/download/engine/webview/runtime.go#L576-L612","documentation":"The last-resort branch of NormalizeExecutableValue: the value is a goja.Value that is neither a string nor a callable object, and its String() rendering does not look like function source (looksLikeFunctionSource). Both the Go type and the stringified value are reported, so the message shows exactly what was passed — commonly a plain object rendering as \"[object Object]\".","triggerScenarios":"page.execute({selector: '#x'}) or page.execute(123n)/page.execute(true) from JS; passing a DOM element, array, or serialized handle instead of a function; passing an object whose toString was overridden to non-function text.","commonSituations":"Confusing execute(page.waitForSelector(...)-style handle objects) with source; passing a parsed JSON config where a callback source string was expected; arrow functions already stringified but wrapped in extra quotes (a string containing quotes would take the string branch, so this is typically a genuine non-function object).","solutions":["Wrap the intent in a function: page.execute(() => ({selector: '#x'}))","Pass expression source as a plain string: page.execute('document.title')","Inspect the (%q) part of the message to see what the value actually stringified to, then fix the call site"],"exampleFix":"// before\nawait page.execute({ selector: '#x' }); // got *goja.Object (\"[object Object]\")\n// after\nawait page.execute(() => document.querySelector('#x') !== null);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// JS: narrow to string/function before execute (objects like element handles fail here)\nfunction isExecutable(x) {\n  if (typeof x === 'string' || typeof x === 'function') return true;\n  return false; // numbers, booleans, arrays, plain objects, DOM nodes all fail\n}","tryCatchPattern":null,"preventionTips":["Wrap object data in a function: () => ({...}) instead of passing the object","Check the (%q) fragment in the message to see what actually arrived","Do not pass results of other page APIs (handles, selectors) into execute"],"tags":["webview","execute","type-error","javascript"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}