InvalidCastException: Specified cast is not valid.

Hello everyone, I am a newly started game developer, and some errors occurred while using sqlite as a game save file.

“Most players, including me, have not triggered this error, and a few players will appear with the message” InvalidCastException: Specified cast is not valid. “”

I am not sure what caused this error to occur, and there are several other places where the same error has occurred. Here is only one example.

If you understand the reason, please also let me know. Thank you very much.

The following is an error report

** **PlayerConnection initialized network socket : 0.0.0.0 55331** **Multi-casting "[IP] 10.0.4.10 [Port] 55331 [Flags] 2 [Guid] 3664547826 [EditorId] 1485823174 [Version] 1048832 [Id] WindowsPlayer(SHADOW-22IBQVIN) [Debug] 1 [PackageName] WindowsPlayer [ProjectName] RHOTG" to [225.0.0.222:54997]...** **Started listening to [0.0.0.0:55331]** **Starting managed debugger on port 56826** **Using monoOptions --debugger-agent=transport=dt_socket,embedding=1,server=y,suspend=n,address=0.0.0.0:56826** **PlayerConnection already initialized - listening to [0.0.0.0:55331]** **AS: AutoStreaming module initializing.Initialize engine version: 2020.3.25f1c1 (fd09ccef852e)** **GfxDevice: creating device client; threaded=1** **Direct3D:** **Version: Direct3D 11.0 [level 11.1]** **Renderer: NVIDIA Quadro P5000 (ID=0x1bb0)** **Vendor:** **VRAM: 16248 MB** **Driver: 31.0.15.2698** **Begin MonoManager ReloadAssembly** **- Completed reload, in 0.764 seconds** **<RI> Initializing input.** **<RI> Input initialized.** **<RI> Initialized touch support.** **UnloadTime: 1.303100 ms** **InvalidCastException: Specified cast is not valid.** **at Mono.Data.Sqlite.SqliteDataReader.VerifyType (System.Int32 i, System.Data.DbType typ) [0x000c5] in <afb4049b8dec44e9b329b5b9ee3695f4>:0** **at Mono.Data.Sqlite.SqliteDataReader.GetDouble (System.Int32 i) [0x00025] in <afb4049b8dec44e9b329b5b9ee3695f4>:0** **at SQLiteControl.GetPlayer () [0x002fd] in <c6be8ed08c4240e6bc1d126185519e4c>:0** **at UnityEngine.Events.InvokableCall.Invoke () [0x00010] in <266baf6fd8b54ff78f3e83ce38a15611>:0** **at UnityEngine.Events.UnityEvent.Invoke () [0x00022] in <266baf6fd8b54ff78f3e83ce38a15611>:0** **at UnityEngine.UI.Button.Press () [0x00027] in <8ae124bdcad146b186dd731d42ef06b4>:0** **at UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) [0x00010] in <8ae124bdcad146b186dd731d42ef06b4>:0** **at UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) [0x00008] in <8ae124bdcad146b186dd731d42ef06b4>:0** **at UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) [0x00074] in <8ae124bdcad146b186dd731d42ef06b4>:0** **UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)** **UnityEngine.DebugLogHandler:LogException(Exception, Object)** **UnityEngine.Logger:LogException(Exception, Object)** **UnityEngine.Debug:LogException(Exception)** **UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)** **UnityEngine.EventSystems.StandaloneInputModule:ReleaseMouse(PointerEventData, GameObject)** **UnityEngine.EventSystems.StandaloneInputModule:ProcessMousePress(MouseButtonEventData)** **UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent(Int32)** **UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent()** **UnityEngine.EventSystems.StandaloneInputModule:Process()** **UnityEngine.EventSystems.EventSystem:Update()** **
The following is the “GetPlayer()” code block
```csharp
** public void GetPlayer()
{

    reader_Save = sql.ReadTable("save", new string[] { "p_name","p_lv","p_exp","p_exp_now","p_hp","p_teh","p_agile","p_vision","p_luck","p_dodge",
        "p_lv_point","p_s_point","p_money","p_killed","p_killed_boss","p_drop_count","p_max_damage",
        "s_lv_1","s_lv_2","s_lv_3","s_lv_4","s_lv_5","s_lv_6","z_id","p_pack",
        "p_teh_temp","p_agile_temp","p_vision_temp","p_luck_temp","s_lv_2_temp","s_lv_3_temp","s_lv_4_temp","s_lv_5_temp","s_lv_6_temp","p_death"}, new string[] { "p_id" }, new string[] { "=" }, new string[] { "'" + save_slot + "'" });

    while (reader_Save.Read())
    {

        PlayerControl.Instance.playerName = reader_Save.GetString(reader_Save.GetOrdinal("p_name")).ToString();
        PlayerControl.Instance.playerLv = reader_Save.GetInt32(reader_Save.GetOrdinal("p_lv"));
        PlayerControl.Instance.playerEXP = reader_Save.GetInt32(reader_Save.GetOrdinal("p_exp"));
        PlayerControl.Instance.playerEXP_Now = reader_Save.GetInt32(reader_Save.GetOrdinal("p_exp_now"));
        PlayerControl.Instance.playerHP = reader_Save.GetInt32(reader_Save.GetOrdinal("p_hp"));
        PlayerControl.Instance.playerTechnic = reader_Save.GetInt32(reader_Save.GetOrdinal("p_teh"));
        PlayerControl.Instance.playerAgile = reader_Save.GetInt32(reader_Save.GetOrdinal("p_agile"));
        PlayerControl.Instance.playerVis = reader_Save.GetInt32(reader_Save.GetOrdinal("p_vision"));
        PlayerControl.Instance.playerLuck = reader_Save.GetInt32(reader_Save.GetOrdinal("p_luck"));
        PlayerControl.Instance.dodge = reader_Save.GetDouble(reader_Save.GetOrdinal("p_dodge"));
        PlayerControl.Instance.lvPoint = reader_Save.GetInt32(reader_Save.GetOrdinal("p_lv_point"));
        PlayerControl.Instance.skillPoint = reader_Save.GetInt32(reader_Save.GetOrdinal("p_s_point"));
        PlayerControl.Instance.money = reader_Save.GetInt32(reader_Save.GetOrdinal("p_money"));
        PlayerControl.Instance.Log_Monster = reader_Save.GetInt32(reader_Save.GetOrdinal("p_killed"));
        PlayerControl.Instance.Log_Boss = reader_Save.GetInt32(reader_Save.GetOrdinal("p_killed_boss"));
        PlayerControl.Instance.Log_Item = reader_Save.GetInt32(reader_Save.GetOrdinal("p_drop_count"));
        PlayerControl.Instance.Log_Damage = reader_Save.GetInt64(reader_Save.GetOrdinal("p_max_damage"));
        PlayerControl.Instance.skill_1_lv = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_1"));
        PlayerControl.Instance.skill_2_lv = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_2"));
        PlayerControl.Instance.skill_3_lv = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_3"));
        PlayerControl.Instance.skill_4_lv = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_4"));
        PlayerControl.Instance.skill_5_lv = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_5"));
        PlayerControl.Instance.skill_6_lv = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_6"));
        PlayerControl.Instance.zone = reader_Save.GetInt32(reader_Save.GetOrdinal("z_id"));
        PlayerControl.Instance.playerPack = reader_Save.GetInt32(reader_Save.GetOrdinal("p_pack"));
        PlayerControl.Instance.playerTechnicTemp = reader_Save.GetInt32(reader_Save.GetOrdinal("p_teh_temp"));
        PlayerControl.Instance.playerAgileTemp = reader_Save.GetInt32(reader_Save.GetOrdinal("p_agile_temp"));
        PlayerControl.Instance.playerVisTemp = reader_Save.GetInt32(reader_Save.GetOrdinal("p_vision_temp"));
        PlayerControl.Instance.playerLuckTemp = reader_Save.GetInt32(reader_Save.GetOrdinal("p_luck_temp"));

        PlayerControl.Instance.skill_2_temp = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_2_temp"));
        PlayerControl.Instance.skill_3_temp = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_3_temp"));
        PlayerControl.Instance.skill_4_temp = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_4_temp"));
        PlayerControl.Instance.skill_5_temp = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_5_temp"));
        PlayerControl.Instance.skill_6_temp = reader_Save.GetInt32(reader_Save.GetOrdinal("s_lv_6_temp"));
        PlayerControl.Instance.Log_Death = reader_Save.GetInt32(reader_Save.GetOrdinal("p_death"));
       

    }

}**
** **The following is the SQLlite function block** **csharp
**using UnityEngine;
using System.Collections;
using Mono.Data.Sqlite;
using System;

public class SQLiteHelper
{

/// </summary>
private SqliteConnection dbConnection;


/// </summary>
private SqliteCommand dbCommand;


/// </summary>
private SqliteDataReader dataReader;


/// </summary>
public SQLiteHelper(string connectionString)
{
    try
    {
        
        dbConnection = new SqliteConnection(connectionString);
        
        dbConnection.Open();
    }
    catch (Exception e)
    {
        Debug.Log(e.Message);
    }
}


/// </summary>
/// <returns>The query.</returns>
public SqliteDataReader ExecuteQuery(string queryString)
{
    dbCommand = dbConnection.CreateCommand();
    dbCommand.CommandText = queryString;
    dataReader = dbCommand.ExecuteReader();
    return dataReader;
}

/// </summary>
public void CloseConnection()
{
    if (dbCommand != null)
    {
        dbCommand.Cancel();
    }
    dbCommand = null;

    if (dataReader != null)
    {
        dataReader.Close();
    }
    dataReader = null;

    if (dbConnection != null)
    {
        dbConnection.Close();
    }
    dbConnection = null;
}


/// </summary>
/// <returns>The full table.</returns>
public SqliteDataReader ReadFullTable(string tableName)
{
    string queryString = "SELECT * FROM " + tableName;
    return ExecuteQuery(queryString);
}

/// </summary>
/// <returns>The values.</returns>
public SqliteDataReader InsertValues(string tableName, string[] values)
{

    int fieldCount = ReadFullTable(tableName).FieldCount;

    if (values.Length != fieldCount)
    {
        throw new SqliteException("values.Length!=fieldCount");
    }

    string queryString = "INSERT INTO " + tableName + " VALUES (" + values[0];
    for (int i = 1; i < values.Length; i++)
    {
        queryString += ", " + values[i];
    }
    queryString += " )";
    return ExecuteQuery(queryString);
}


/// </summary>
/// <returns>The values.</returns>

public SqliteDataReader UpdateValues(string tableName, string[] colNames, string[] colValues, string key, string operation, string value)
{

    if (colNames.Length != colValues.Length)
    {
        throw new SqliteException("colNames.Length!=colValues.Length");
    }

    string queryString = "UPDATE " + tableName + " SET " + colNames[0] + "=" + colValues[0];
    for (int i = 1; i < colValues.Length; i++)
    {
        queryString += ", " + colNames[i] + "=" + colValues[i];
    }
    queryString += " WHERE " + key + operation + value;
    return ExecuteQuery(queryString);
}


/// </summary>
/// <returns>The values.</returns>
public SqliteDataReader DeleteValuesOR(string tableName, string[] colNames, string[] operations, string[] colValues)
{

    if (colNames.Length != colValues.Length || operations.Length != colNames.Length || operations.Length != colValues.Length)
    {
        throw new SqliteException("colNames.Length!=colValues.Length || operations.Length!=colNames.Length || operations.Length!=colValues.Length");
    }

    string queryString = "DELETE FROM " + tableName + " WHERE " + colNames[0] + operations[0] + colValues[0];
    for (int i = 1; i < colValues.Length; i++)
    {
        queryString += "OR " + colNames[i] + operations[0] + colValues[i];
    }
    return ExecuteQuery(queryString);
}


/// </summary>
/// <returns>The values.</returns>
public SqliteDataReader DeleteValuesAND(string tableName, string[] colNames, string[] operations, string[] colValues)
{
    if (colNames.Length != colValues.Length || operations.Length != colNames.Length || operations.Length != colValues.Length)
    {
        throw new SqliteException("colNames.Length!=colValues.Length || operations.Length!=colNames.Length || operations.Length!=colValues.Length");
    }

    string queryString = "DELETE FROM " + tableName + " WHERE " + colNames[0] + operations[0] + colValues[0];
    for (int i = 1; i < colValues.Length; i++)
    {
        queryString += " AND " + colNames[i] + operations[i] + colValues[i];
    }
    return ExecuteQuery(queryString);
}

/// </summary> +
/// <returns>The table.</returns>
public SqliteDataReader CreateTable(string tableName, string[] colNames, string[] colTypes)
{
    string queryString = "CREATE TABLE " + tableName + "( " + colNames[0] + " " + colTypes[0];
    for (int i = 1; i < colNames.Length; i++)
    {
        queryString += ", " + colNames[i] + " " + colTypes[i];
    }
    queryString += "  ) ";
    return ExecuteQuery(queryString);
}

/// <summary>
/// Reads the table.
/// </summary>
/// <returns>The table.</returns>
/// <param name="tableName">Table name.</param>
/// <param name="items">Items.</param>
/// <param name="colNames">Col names.</param>
/// <param name="operations">Operations.</param>
/// <param name="colValues">Col values.</param>
public SqliteDataReader ReadTable(string tableName, string[] items, string[] colNames, string[] operations, string[] colValues)
{
    string queryString = "SELECT " + items[0];
    for (int i = 1; i < items.Length; i++)
    {
        queryString += ", " + items[i];
    }
    queryString += " FROM " + tableName + " WHERE " + colNames[0] + " " + operations[0] + " " + colValues[0];
    for (int i = 0; i < colNames.Length; i++)
    {
        queryString += " AND " + colNames[i] + " " + operations[i] + " " + colValues[0] + " ";
    }
    return ExecuteQuery(queryString);
}

}**
** **The following are the "Player" properties** **csharp
public class PlayerControl : MonoBehaviour
{
public string playerName = " ";
public int playerLv = 1;
public int playerEXP = 300;
public int playerEXP_Now = 0;
public int playerHP = 100;
public int playerTechnic = 1;
public int playerAgile = 1;
public int playerVis = 1;
public int playerLuck = 1;
public double dodge = 10;
public int lvPoint = 0;
public int skillPoint = 0;
public int money = 0;
public int Log_Monster = 0;
public int Log_Boss = 0;
public int Log_Item = 0;
public long Log_Damage = 0;
public int skill_1_lv = 1;
public int skill_2_lv = 0;
public int skill_3_lv = 0;
public int skill_4_lv = 0;
public int skill_5_lv = 0;
public int skill_6_lv = 0;
public int zone = 10;
public int playerPack = 10;
public int playerTechnicTemp = 0;
public int playerAgileTemp = 0;
public int playerVisTemp = 0;
public int playerLuckTemp = 0;
public int skill_2_temp = 0;
public int skill_3_temp = 0;
public int skill_4_temp = 0;
public int skill_5_temp = 0;
public int skill_6_temp = 0;
public int Log_Death = 0;
}

```
database structure

A better question is why you saw fit to use a sql database here, when it would much easier to serialise plain data to JSON, as is much more standard in game dev.

I am trying to use various unused tools, and this time I chose sqlite for development.
So, do you have any opinions on the occurrence of this error?

I mean it’s happening at dodge, which is your only double so make sure it’s always being written as a double (why is a double too?).

But honestly, there’s no reason to be using sql here. You’re adding a lot of unnecessary complexity when PlayerControl could just be a plain C# class that you read/write with JSON. 100x easier.

Oh, thank you for your reminder. I have also found that this error always occurs with “double”. Although I am not yet sure what caused it or why some computers can operate normally, some do not.
But at least it’s a good start. Thank you very much for your answer.
As for why not use “json”, I can probably only say, don’t speculate about beginners doing stupid things.
:sweat_smile: