Repository: huggingface/transformers
Pull request: Fix misleading WandB error when WANDB_DISABLED is set

## Fix misleading error message when `WANDB_DISABLED` is set

### Summary

✅ Fixed the misleading WandB error in `src/transformers/integrations/integration_utils.py:814`.

**Before (confusing error):**

```
RuntimeError: WandbCallback requires wandb to be installed. Run `pip install wandb`.
```

**After (clearer error with actionable guidance):**

```
RuntimeError: You specified `report_to='wandb'` but also set the `WANDB_DISABLED` environment variable.
This disables wandb logging, even though it was explicitly requested.

- To enable wandb logging: unset `WANDB_DISABLED`.
- To disable logging: use `report_to='none'`.

Note: WANDB_DISABLED is deprecated and will be removed in v5.
```

### Details

The previous error message was shown even when `wandb` **was installed**, but disabled via the `WANDB_DISABLED` environment variable. This could mislead users into thinking `wandb` wasn’t installed at all.

This PR:

* Detects when `wandb` is installed but explicitly disabled.
* Raises a targeted error with guidance on how to proceed.
* Preserves the original error message if `wandb` is not installed.

### Implementation

Here is the relevant change:

```python
has_wandb = is_wandb_available()
if not has_wandb:
    # Check if wandb is actually installed but disabled via WANDB_DISABLED
    if importlib.util.find_spec("wandb") is not None:
        wandb_disabled = os.getenv("WANDB_DISABLED", "").upper() in ENV_VARS_TRUE_VALUES
        if wandb_disabled:
            raise RuntimeError(
                "You specified `report_to='wandb'` but also set the `WANDB_DISABLED` environment variable.\n"
                "This disables wandb logging, even though it was explicitly requested.\n\n"
                "- To enable wandb logging: unset `WANDB_DISABLED`.\n"
                "- To disable logging: use `report_to='none'`.\n\n"
                "Note: WANDB_DISABLED is deprecated and will be removed in v5."
            )
    raise RuntimeError("WandbCallback requires wandb to be installed. Run `pip install wandb`.")
```

### Testing

✅ Manually tested using the following script:

```
import os
import importlib.util
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM
from trl import SFTTrainer, SFTConfig
import logging

# Simulate W&B being disabled, even though it's installed
os.environ["WANDB_DISABLED"] = "true"

# Optionally set up logging to see the deprecation warning
logging.basicConfig(level=logging.WARNING)

# Confirm wandb is installed but will be treated as unavailable
print("WandB is installed:", importlib.util.find_spec("wandb") is not None)

# Load tokenizer and model (replace with a smaller model if needed for quick tests)
model_name = "gpt2"  # Replace with a small HF model if you don't have access
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(model_name, trust_remote_code=True)

tokenizer.pad_token = tokenizer.eos_token

# Create a simple dummy dataset
texts = ["Hello, how are you?", "What's the capital of France?"]
dataset = Dataset.from_dict({"text": texts})

# Tokenize
def tokenize(example):
    return tokenizer(example["text"], padding="max_length", truncation=True, max_length=64)

tokenized_dataset = dataset.map(tokenize)

# SFTConfig with WandB enabled, but WANDB_DISABLED is also set
training_args = SFTConfig(
    output_dir="./outputs",
    per_device_train_batch_size=1,
    num_train_epochs=1,
    logging_steps=1,
    learning_rate=1e-5,
    report_to="wandb",  # 👈 This triggers the issue
    run_name="test-wandb-conflict",
)

# Trainer setup
trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    tokenizer=tokenizer,
)

# This will trigger the warning and the misleading RuntimeError
trainer.train()
```

the new error message appears correctly when `WANDB_DISABLED=true`.

---

This PR fixes #39878.

Changed files:
filename: src/transformers/integrations/integration_utils.py
patch: @@ -806,6 +806,19 @@ class WandbCallback(TrainerCallback):
     def __init__(self):
         has_wandb = is_wandb_available()
         if not has_wandb:
+            # Check if wandb is actually installed but disabled via WANDB_DISABLED
+            if importlib.util.find_spec("wandb") is not None:
+                # wandb is installed but disabled
+                wandb_disabled = os.getenv("WANDB_DISABLED", "").upper() in ENV_VARS_TRUE_VALUES
+                if wandb_disabled:
+                    raise RuntimeError(
+                        "You specified `report_to='wandb'` but also set the `WANDB_DISABLED` environment variable.\n"
+                        "This disables wandb logging, even though it was explicitly requested.\n\n"
+                        "- To enable wandb logging: unset `WANDB_DISABLED`.\n"
+                        "- To disable logging: use `report_to='none'`.\n\n"
+                        "Note: WANDB_DISABLED is deprecated and will be removed in v5."
+                    )
+            # If wandb is not installed at all, use the original error message
             raise RuntimeError("WandbCallback requires wandb to be installed. Run `pip install wandb`.")
         if has_wandb:
             import wandb