mono/mono · error · TypeError
Cannot convert '{}' to '{}'
Error message
Cannot convert '{}' to '{}' What it means
Raised by the from_param classmethod of the custom c_char_p subclass (the Python3 interop string type) used by the libclang ctypes bindings. ctypes calls from_param to coerce each argument to the declared C type; here only str, bytes, and None are accepted. Any other type falls through all isinstance checks and raises TypeError naming both the offending type and the target class.
Source
Thrown at mono/tools/offsets-tool/clang/cindex.py:100
def __str__(self):
return self.value
@property
def value(self):
if super(c_char_p, self).value is None:
return None
return super(c_char_p, self).value.decode("utf8")
@classmethod
def from_param(cls, param):
if isinstance(param, str):
return cls(param)
if isinstance(param, bytes):
return cls(param)
if param is None:
# Support passing null to C functions expecting char arrays
return None
raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__))
@staticmethod
def to_python_string(x, *args):
return x.value
def b(x):
if isinstance(x, bytes):
return x
return x.encode('utf8')
elif sys.version_info[0] == 2:
# Python 2 strings are utf8 byte strings, no translation is needed for
# C-interop.
c_interop_string = c_char_p
def _to_python_string(x, *args):
return x
View on GitHub (pinned to 0f53e9e151)
Solutions
- Convert the argument to str or bytes before the call: wrap Path values with str(...) or os.fspath(...).
- If you intend to pass a null pointer, pass Python None explicitly rather than 0 or an empty container.
- Inspect the binding's argtypes for the failing function and match the declared c_interop_string / c_char_p expectation.
- Use the higher-level cindex.py wrappers (which already call fspath/b) instead of calling conf.lib.* clang functions directly.
Example fix
# before conf.lib.clang_parseTranslationUnit(idx, some_pathlib_path, args, len(args), None, 0, 0) # TypeError: Cannot convert 'PosixPath' to 'c_char_p' # after from ctypes import c_char_p conf.lib.clang_parseTranslationUnit(idx, str(some_pathlib_path), args, len(args), None, 0, 0)
Defensive patterns
Strategy: type-guard
Validate before calling
def _as_str_or_none(v):
if v is None or isinstance(v, (str, bytes)):
return v
raise TypeError(f'expected str/bytes/None, got {type(v).__name__}') Type guard
def isInteropString(v): return v is None or isinstance(v, (str, bytes))
Prevention
- Always convert pathlib.Path via os.fspath/str before ctypes calls.
- Prefer the high-level cindex wrappers (which call fspath/b) over direct conf.lib.* calls.
- Pass None explicitly for null pointers, never 0.
When it happens
Trigger: A libclang function declared with an argument of this c_interop_string type is called with a value that is not str, bytes, or None — e.g. an int (a file descriptor), a pathlib.Path passed without fspath conversion, a list, or a ctypes object. from_param is invoked by ctypes at call time, so the error surfaces at the clang_* call site.
Common situations: Passing a Path object directly to a function that expects a filename string (most bindings wrap these with fspath(), but a direct ctypes call or a custom binding does not). Passing an integer or None-like sentinel that is not literally None. Mixing str and bytes incorrectly across Python 2/3 code paths.
Related errors
- Invalid format options
- Must supply a non-negative int.
- Only non-negative indexes are accepted.
- Argument could not be retrieved.
- Element type not available on this type.
AI-assisted analysis of mono/mono@0f53e9e151 (2026-08-13).
Data as JSON: /api/errors/062f85a3b5c5564a.
Report an issue: GitHub.