{"record":{"id":"7c940c4eac76f795","repo":"hiyouga/LlamaFactory","slug":"ppo-only-accepts-wandb-tensorboard-or-trackio-lo","errorCode":null,"errorMessage":"PPO only accepts wandb, tensorboard, or trackio logger.","messagePattern":"PPO only accepts wandb, tensorboard, or trackio logger\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/llamafactory/hparams/parser.py","lineNumber":466,"sourceCode":"        raise ValueError(\"RM and PPO stages do not support `load_best_model_at_end`.\")\n\n    if finetuning_args.stage == \"ppo\":\n        if not training_args.do_train:\n            raise ValueError(\"PPO training does not support evaluation, use the SFT stage to evaluate models.\")\n\n        if model_args.shift_attn:\n            raise ValueError(\"PPO training is incompatible with S^2-Attn.\")\n\n        if finetuning_args.reward_model_type == \"lora\" and model_args.use_kt:\n            raise ValueError(\"KTransformers does not support lora reward model.\")\n\n        if finetuning_args.reward_model_type == \"lora\" and model_args.use_unsloth:\n            raise ValueError(\"Unsloth does not support lora reward model.\")\n\n        if training_args.report_to and any(\n            logger not in (\"wandb\", \"tensorboard\", \"trackio\", \"none\") for logger in training_args.report_to\n        ):\n            raise ValueError(\"PPO only accepts wandb, tensorboard, or trackio logger.\")\n\n    if not model_args.use_kt and training_args.parallel_mode == ParallelMode.NOT_DISTRIBUTED:\n        raise ValueError(\"Please launch distributed training with `llamafactory-cli` or `torchrun`.\")\n\n    if training_args.deepspeed and training_args.parallel_mode != ParallelMode.DISTRIBUTED:\n        raise ValueError(\"Please use `FORCE_TORCHRUN=1` to launch DeepSpeed training.\")\n\n    if training_args.max_steps == -1 and data_args.streaming:\n        raise ValueError(\"Please specify `max_steps` in streaming mode.\")\n\n    if training_args.do_train and data_args.dataset is None:\n        raise ValueError(\"Please specify dataset for training.\")\n\n    if (training_args.do_eval or training_args.do_predict or training_args.predict_with_generate) and (\n        data_args.eval_dataset is None and data_args.val_size < 1e-6\n    ):\n        raise ValueError(\"Please make sure eval_dataset be provided or val_size >1e-6\")\n","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/hiyouga/LlamaFactory/blob/f28afaf6355af515454dfb16c97d728307c93897/src/llamafactory/hparams/parser.py#L448-L484","documentation":"This ValueError comes from the PPO-specific validation block in _check_args (src/llamafactory/hparams/parser.py:466). It rejects any `report_to` entry other than wandb, tensorboard, trackio, or the literal string \"none\" when the training stage is PPO. The restriction exists because TRL's PPO trainer only integrates with these logging backends.","triggerScenarios":"Running `llamafactory-cli train` with a config where finetuning_args.stage == \"ppo\" and training_args.report_to contains something else, e.g. report_to: [\"mlflow\"], [\"clearml\"], or [\"codecarbon\"]. The check `any(logger not in (\"wandb\",\"tensorboard\",\"trackio\",\"none\") for logger in report_to)` fires.","commonSituations":"Copying an SFT config (which permits other loggers via the same field) and switching stage to ppo; enabling an experiment-tracking integration (mlflow/aim/clearml) globally in TrainingArguments defaults; HF `report_to=\"all\"` resolving to multiple backends.","solutions":["Set `report_to: wandb` (or `tensorboard` / `trackio`) in the PPO YAML config","To disable logging entirely, set `report_to: none` (or leave report_to empty/null)","Remove mlflow/clearml/aim or other unsupported entries from the config's report_to list"],"exampleFix":"# before (YAML)\nstage: ppo\nreport_to:\n  - mlflow\n\n# after\nstage: ppo\nreport_to: wandb","handlingStrategy":"validation","validationCode":"ALLOWED = {\"wandb\", \"tensorboard\", \"trackio\", \"none\"}\nreport_to = config.get(\"report_to\") or []\nif config.get(\"stage\") == \"ppo\" and any(x not in ALLOWED for x in report_to):\n    raise SystemExit(f\"PPO only allows {sorted(ALLOWED)}; got {report_to}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate report_to against the allowed set before launching PPO runs","Keep separate YAML templates per stage (sft vs ppo) instead of editing one shared file","Add a CI lint step that parses configs and asserts stage-specific constraints"],"tags":["ppo","rlhf","logging","wandb","tensorboard","config-validation"],"backgroundTag":null,"analyzedSha":"f28afaf6355af515454dfb16c97d728307c93897","analyzedAt":"2026-08-14T21:57:28.298Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}