Repository: optuna/optuna
Issue category: Bug Report

Issue:
CLI for empty DB raises `ValueError`
### Expected behavior

CLI for empty DB should output empty result, but the current implementation raises `ValueError`.

### Environment

- Optuna version:4.2.0.dev
- Python version:3.13.0
- OS:macOS-15.1-x86_64-i386-64bit-Mach-O
- (Optional) Other libraries and their versions:

### Error messages, stack traces, or logs

```shell
See below.
```


### Steps to reproduce

For empty DB (`tmp.db` does not exist before the command), the `optuna studies` command raises `ValueError`.

```bash
$ optuna --storage sqlite:///tmp.db studies
Traceback (most recent call last):
  File "/Users/naotomizuno/.pyenv/versions/optuna-3.13.0/bin/optuna", line 8, in <module>
    sys.exit(main())
             ~~~~^^
  File "/Users/naotomizuno/optuna/optuna/cli.py", line 991, in main
    return args.handler(args)
           ~~~~~~~~~~~~^^^^^^
  File "/Users/naotomizuno/optuna/optuna/cli.py", line 463, in take_action
    _format_output(
    ~~~~~~~~~~~~~~^
        records, self._study_list_header, parsed_args.format, parsed_args.flatten
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/naotomizuno/optuna/optuna/cli.py", line 258, in _format_output
    return _dump_table(values, header).strip()
           ~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/Users/naotomizuno/optuna/optuna/cli.py", line 222, in _dump_table
    max_width = max(len(header[column]), max(row[column].width() for row in rows))
                                         ~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: max() iterable argument is empty
```


### Additional context (optional)

_No response_


Hints:

Patch:
diff --git a/optuna/cli.py b/optuna/cli.py
index 16fa3a6df1..7246a86e21 100644
--- a/optuna/cli.py
+++ b/optuna/cli.py
@@ -215,7 +215,10 @@ def _dump_table(records: list[dict[str, Any]], header: list[str]) -> str:
         for t in value_types:
             if t == ValueType.STRING:
                 value_type = ValueType.STRING
-        max_width = max(len(header[column]), max(row[column].width() for row in rows))
+        if len(rows) == 0:
+            max_width = len(header[column])
+        else:
+            max_width = max(len(header[column]), max(row[column].width() for row in rows))
         separator += "-" * (max_width + 2) + "+"
         if value_type == ValueType.NUMERIC:
             header_string += f" {header[column]:>{max_width}} |"
@@ -228,7 +231,8 @@ def _dump_table(records: list[dict[str, Any]], header: list[str]) -> str:
     ret += separator + "\n"
     ret += header_string + "\n"
     ret += separator + "\n"
-    ret += "\n".join(rows_string) + "\n"
+    for row_string in rows_string:
+        ret += row_string + "\n"
     ret += separator + "\n"
 
     return ret


Test patch: