{"record":{"id":"3b7889a210d98ac9","repo":"tursodatabase/turso","slug":"native-error-message-via-marshal-ptrtostringutf8","errorCode":null,"errorMessage":"{native error message via Marshal.PtrToStringUTF8}","messagePattern":"\\{native error message via Marshal\\.PtrToStringUTF8\\}","errorType":"exception","errorClass":"TursoSyncNativeException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Raw/Public/TursoSyncBindings.cs","lineNumber":466,"sourceCode":"        => slice.Length == 0 ? string.Empty : Encoding.UTF8.GetString(CopyBytes(slice));\n\n    private static void ThrowIfError(TursoStatusCode status, IntPtr errorPtr)\n    {\n        if (errorPtr != IntPtr.Zero)\n            ThrowException(status, errorPtr);\n        if (status == TursoStatusCode.Ok)\n            return;\n\n        throw new TursoSyncNativeException(\n            (uint)status,\n            $\"Turso sync native call failed with status {status}.\");\n    }\n\n    private static void ThrowException(TursoStatusCode status, IntPtr errorPtr)\n    {\n        var message = Marshal.PtrToStringUTF8(errorPtr) ?? \"Internal error\";\n        TursoSyncInterop.FreeString(errorPtr);\n        throw new TursoSyncNativeException((uint)status, message);\n    }\n\n    private static void ReleaseConnection(IntPtr connection)\n    {\n        _ = TursoInterop.ConnectionClose(connection, out var errorPtr);\n        if (errorPtr != IntPtr.Zero)\n            TursoInterop.FreeString(errorPtr);\n        TursoInterop.ConnectionDeinit(connection);\n    }\n\n    private sealed class NativeUtf8String : IDisposable\n    {\n        private NativeUtf8String(IntPtr pointer) => Pointer = pointer;\n\n        public IntPtr Pointer { get; private set; }\n\n        public static NativeUtf8String From(string? value)\n            => new(value is null ? IntPtr.Zero : Marshal.StringToCoTaskMemUTF8(value));","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/bindings/dotnet/src/Turso.Raw/Public/TursoSyncBindings.cs#L448-L484","documentation":"This is the catch-all native interop exception in the .NET Turso sync bindings. When a P/Invoke call into the native tursodb library returns a non-zero error pointer or a non-OK status code, ThrowException converts the native UTF-8 error string into a managed TursoSyncNativeException carrying the status code and the native message. It means the failure originated inside the native library (SQL error, invalid handle, sync failure), not in the managed wrapper.","triggerScenarios":"Any call into the raw sync bindings (Resume, cursor/step calls, sync operations) where the native side returns an errorPtr or status != Ok. E.g. executing SQL with a syntax error on a native connection, using a closed/disposed connection handle, or a native sync failure.","commonSituations":"SQL syntax or constraint violations raised by the engine, calling methods after the connection was closed or freed, native library version mismatch with the managed wrapper, or platform-specific native failures (file I/O, locking) surfaced through the error pointer.","solutions":["Read the exception's message and status code: the native message is the real diagnostic, not the .NET stack trace.","Check the surrounding code for use-after-close/dispose of the connection or cursor before the failing call.","Reproduce the same SQL/operation in the tursodb CLI to see if the native engine itself rejects it (vs a binding misuse).","Verify the native tursodb binary matches the version the .NET bindings were compiled against; re-pin the package versions.","Wrap calls in try/catch on TursoSyncNativeException and inspect the status code for retryable (I/O) vs permanent (SQL) errors."],"exampleFix":"// before\nconnection.Execute(sql); // may throw TursoSyncNativeException with raw native message\n// after\ntry\n{\n    connection.Execute(sql);\n}\ncatch (TursoSyncNativeException ex)\n{\n    Console.Error.WriteLine($\"Turso native error {ex.StatusCode}: {ex.Message}\");\n    if (!IsRetryable(ex.StatusCode)) throw;\n}","handlingStrategy":"try-catch","validationCode":"// verify handle liveness before native calls\nif (connection.IsClosed) throw new InvalidOperationException(\"connection already closed\");","typeGuard":"static bool HasNativeError(IntPtr errorPtr) => errorPtr != IntPtr.Zero;","tryCatchPattern":"try\n{\n    nativeCall();\n}\ncatch (TursoSyncNativeException ex)\n{\n    // ex.StatusCode distinguishes retryable I/O from permanent SQL errors\n    Log(ex.StatusCode, ex.Message);\n    if (!IsRetryable(ex.StatusCode)) throw;\n}","preventionTips":["Always read the exception message — it carries the native library's diagnostic.","Never use connection/cursor objects after Dispose.","Keep the native binary and .NET binding versions in lockstep.","Test the failing SQL directly in tursodb CLI to separate SQL errors from binding misuse."],"tags":["csharp","dotnet","interop","native","pinvoke"],"backgroundTag":"native-interop-error","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-31T11:17:35.598Z","contentChangedAt":"2026-08-31T11:17:35.598Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}