{"record":{"id":"3bfc4c52fb044e0b","repo":"unslothai/unsloth","slug":"no-valid-conversation-column-found-in-dataset-col","errorCode":null,"errorMessage":"No valid conversation column found in {dataset.column_names}. Expected a 'conversations' column with 'from'/'value' or 'role'/'content' turn keys.","messagePattern":"No valid conversation column found in (.+?)\\. Expected a 'conversations' column with 'from'/'value' or 'role'/'content' turn keys\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/utils/datasets/dataset_none_detect.py","lineNumber":390,"sourceCode":"            if len(row_findings) == len(conversation):\n                stats[\"rows_all_none\"] += 1\n\n    return stats\n\n\n# ---------------------------------------------------------------------------\n# Convenience wrappers per format (all delegate to the same scan logic)\n# ---------------------------------------------------------------------------\n\n\ndef find_none_sharegpt(dataset: Dataset, col: str = None) -> dict:\n    \"\"\"ShareGPT uses 'from'/'value' keys - same scan logic handles both.\"\"\"\n    if col is None:\n        # ShareGPT lives in 'conversations'; probe only that column so a corrupt\n        # one is still scanned, not replaced by healthy 'messages' (P1 fix).\n        conv_info = _probe_conversation(dataset, candidates = (\"conversations\",))\n        if conv_info is None:\n            raise ValueError(\n                f\"No valid conversation column found in {dataset.column_names}. \"\n                \"Expected a 'conversations' column with 'from'/'value' or 'role'/'content' turn keys.\"\n            )\n        col = conv_info[\"column\"]\n    return find_none_chatml(dataset, col = col)\n\n\ndef find_none_gptoss(dataset: Dataset, col: str = None) -> dict:\n    \"\"\"gptoss: role/content plus optional thinking/tool_calls. Only content checked.\"\"\"\n    if col is None:\n        # gptoss lives in 'messages': target it whenever present (even if\n        # corrupt); fall back to 'conversations' only if 'messages' is absent.\n        if \"messages\" in dataset.column_names:\n            conv_info = _probe_conversation(dataset, candidates = (\"messages\",))\n        else:\n            conv_info = _probe_conversation(dataset, candidates = (\"conversations\",))\n        if conv_info is None:\n            raise ValueError(","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/datasets/dataset_none_detect.py#L372-L408","documentation":"ValueError from find_none_sharegpt when column auto-detection fails: _probe_conversation was restricted to the single candidate 'conversations' (so a healthy 'messages' column never substitutes for a corrupt 'conversations' one), and probing that column found no turns with 'from'/'value' or 'role'/'content' keys. Without a structurally valid conversations column there is no ShareGPT data to scan.","triggerScenarios":"Calling find_none_sharegpt(dataset) where the dataset has no 'conversations' column at all, or has one whose turn dicts use unrecognized keys (e.g. {'speaker','text'}) or are not dicts (strings/None).","commonSituations":"Datasets exported from custom pipelines with renamed keys; rows where conversations is null so the probe sees no valid turn keys; assuming ShareGPT format because the loader name says so while the actual schema is Alpaca or plain text.","solutions":["Rename your conversation column to 'conversations' and make each turn a dict with 'from'/'value' or 'role'/'content' keys","Pass the column explicitly if it exists but is named differently AND has valid turn keys: find_none_sharegpt(dataset, col='...')","If the data is actually role/content chatml, scan with fmt='chatml' instead of 'sharegpt'"],"exampleFix":"# before\nstats = find_none_sharegpt(dataset)  # column named 'chat', turns use speaker/text\n\n# after\ndataset = dataset.rename_column('chat', 'conversations').map(\n    lambda r: {'conversations': [{'from': t['speaker'], 'value': t['text']} for t in r['conversations']]}\n)\nstats = find_none_sharegpt(dataset)","handlingStrategy":"validation","validationCode":"def is_sharegpt_scannable(dataset) -> bool:\n    if \"conversations\" not in dataset.column_names:\n        return False\n    sample = next(iter(dataset), None)\n    turns = (sample or {}).get(\"conversations\") or []\n    return bool(turns) and isinstance(turns[0], dict) and (\n        {\"from\", \"value\"} <= turns[0].keys() or {\"role\", \"content\"} <= turns[0].keys()\n    )","typeGuard":"def is_sharegpt_turn(turn) -> bool:\n    return isinstance(turn, dict) and (\n        (\"from\" in turn and \"value\" in turn) or (\"role\" in turn and \"content\" in turn)\n    )","tryCatchPattern":null,"preventionTips":["Confirm the column is literally named 'conversations' before choosing fmt='sharegpt'","Check that the first turn is a dict with from/value or role/content keys","A corrupt 'conversations' column is scanned, not replaced — fix the data, don't rely on fallback"],"tags":["datasets","data-quality","sharegpt","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}