GopeedLab/gopeed · error

execute expects a string or function

Error message

execute expects a string or function

What it means

NormalizeExecutableValue is the goja.Value-level entry for executable arguments; its first guard rejects a nil value. A nil reaches it when Go code passes a literal nil (or a nil goja.Value interface) — from the JS side, undefined/null normally take the normalizeExecutable default branch instead, so this is essentially a Go-caller bug.

Source

Thrown at pkg/download/engine/webview/runtime.go:574

		return 100
	}
	return value
}

func normalizeExecutable(scriptOrFn any) (string, error) {
	switch value := scriptOrFn.(type) {
	case string:
		return value, nil
	case *goja.Object:
		return NormalizeExecutableValue(value)
	default:
		return "", fmt.Errorf("execute expects a string or function, got %T", scriptOrFn)
	}
}

func NormalizeExecutableValue(value goja.Value) (string, error) {
	if value == nil {
		return "", fmt.Errorf("execute expects a string or function")
	}
	switch raw := value.Export().(type) {
	case string:
		return raw, nil
	}
	obj, ok := value.(*goja.Object)
	if ok {
		if _, ok := goja.AssertFunction(obj); ok {
			source, err := functionSource(obj)
			if err != nil {
				return "", err
			}
			return normalizeFunctionSource(source), nil
		}
	}
	source := strings.TrimSpace(value.String())
	if looksLikeFunctionSource(source) {
		return normalizeFunctionSource(source), nil

View on GitHub (pinned to 7b7327ffb3)

Solutions

  1. Check the value exists (Get returns non-undefined) before forwarding to NormalizeExecutableValue
  2. Default to a sensible expression string when the argument is absent
  3. Unit-test the host helper with the missing-argument case

Example fix

// before
val := opts.Get("fn") // may be nil
src, err := webview.NormalizeExecutableValue(val)
// after
val := opts.Get("fn")
if val == nil || goja.IsUndefined(val) || goja.IsNull(val) {
    return fmt.Errorf("option 'fn' is required")
}
src, err := webview.NormalizeExecutableValue(val)
Defensive patterns

Strategy: type-guard

Type guard

// Go: presence check before normalizing a goja.Value
func executablePresent(v goja.Value) bool {
    return v != nil && !goja.IsUndefined(v) && !goja.IsNull(v)
}

Prevention

When it happens

Trigger: Calling NormalizeExecutableValue(nil) or a wrapper that forwards an uninitialized goja.Value; Execute helpers reading a map key that was never set and forwarding the zero Value.

Common situations: Host-side plumbing that extracts a callback from an options object and forwards it without checking presence; refactors that dropped an existence check.

Related errors


AI-assisted analysis of GopeedLab/gopeed@7b7327ffb3 (2026-08-16). Data as JSON: /api/errors/3bd1e2006c417524. Report an issue: GitHub.