BoundaryML/baml · error

invalid symbol name: %w

Error message

invalid symbol name: %w

What it means

getSymbol on Windows converts the symbol name to a byte pointer with syscall.BytePtrFromString before calling GetProcAddress. This error means that conversion failed, which occurs only when the symbol name contains a NUL byte. Since symbol names are typically literals in the BAML bindings, this almost always indicates a programmatic construction of the name from a raw buffer.

Source

Thrown at engine/language_client_go/baml_go/lib_windows.go:49

	pathPtr, err := syscall.UTF16PtrFromString(path)
	if err != nil {
		return nil, fmt.Errorf("invalid library path: %w", err)
	}

	handle, _, err := procLoadLibraryW.Call(uintptr(unsafe.Pointer(pathPtr)))
	if handle == 0 {
		lastErr, _, _ := procGetLastError.Call()
		return nil, fmt.Errorf("LoadLibrary failed for %s: error code %d: %w", path, lastErr, err)
	}

	return unsafe.Pointer(handle), nil
}

// getSymbol retrieves a symbol from the loaded library
func getSymbol(handle unsafe.Pointer, name string) (unsafe.Pointer, error) {
	namePtr, err := syscall.BytePtrFromString(name)
	if err != nil {
		return nil, fmt.Errorf("invalid symbol name: %w", err)
	}

	proc, _, err := procGetProcAddress.Call(
		uintptr(handle),
		uintptr(unsafe.Pointer(namePtr)),
	)

	if proc == 0 {
		lastErr, _, _ := procGetLastError.Call()
		return nil, fmt.Errorf("GetProcAddress failed for %s: error code %d: %w", name, lastErr, err)
	}

	return unsafe.Pointer(proc), nil
}

// closeLibrary closes the loaded library
func closeLibrary(handle unsafe.Pointer) error {
	if handle == nil {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Trim NUL bytes from the name before lookup: strings.TrimRight(name, "\x00").
  2. Use static symbol-name literals instead of deriving names from buffers where possible.
  3. Add a validation check strings.ContainsRune(name, 0) before calling the runtime lookup.
  4. If names come from a data file, fix the generator to strip terminators at the source.

Example fix

// before
proc := getSymbol(handle, rawNameFromBuffer) // "baml_fn\x00"

// after
name := strings.TrimRight(rawNameFromBuffer, "\x00")
if strings.ContainsRune(name, 0) {
    return fmt.Errorf("invalid symbol name %q", name)
}
proc := getSymbol(handle, name)
Defensive patterns

Strategy: validation

Validate before calling

if strings.ContainsRune(name, 0) {
    return fmt.Errorf("symbol name contains NUL byte: %q", name)
}

Type guard

func validSymbolName(n string) bool {
    return n != "" && !strings.ContainsRune(n, 0)
}

Try / catch

if _, err := syscall.BytePtrFromString(name); err != nil {
    return fmt.Errorf("bad symbol name: %w", err)
}

Prevention

When it happens

Trigger: getSymbol called with a name string containing an embedded NUL character, e.g. a symbol name sliced from a C buffer or built with byte concatenation without trimming the terminator.

Common situations: Introspection/dynamic-binding code that reads symbol names from binary data; string truncation bugs where the trailing 0x00 is retained; corrupted lookup tables of exported symbol names.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/3d7b20c56069a61c. Report an issue: GitHub.