UmyaSpreadsheet Troubleshooting Guide
View SourceThis guide covers common issues, their solutions, and best practices for using UmyaSpreadsheet effectively.
Table of Contents
- Installation Issues
- Runtime Errors
- Performance Issues
- File Format Issues
- Memory Issues
- Concurrency Issues
- Platform-Specific Issues
- Best Practices
- Debugging Tips
Installation Issues
Problem: NIF Compilation Fails
Symptoms:
** (Mix) could not compile dependency :umya_spreadsheet_ex
Solutions:
Ensure Rust is installed:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.cargo/env
Force rebuild:
export UMYA_SPREADSHEET_BUILD=true mix deps.clean umya_spreadsheet_ex --build mix deps.get mix deps.compile
Check Rust version compatibility:
rustc --version # Should be 1.70.0 or newer
Problem: Precompiled NIF Not Found
Symptoms:
** (RuntimeError) Unable to load NIF
Solutions:
Use force build mode:
# In config/config.exs config :umya_spreadsheet_ex, force_build: true
Check platform compatibility:
mix deps.get mix deps.compile --force
Problem: Apple Silicon (M1/M2) Issues
Symptoms:
** (ArgumentError) errors were found at the given arguments
Solutions:
Install Rust for Apple Silicon:
arch -arm64 brew install rust
Force ARM64 compilation:
export CARGO_TARGET_AARCH64_APPLE_DARWIN_LINKER=clang export UMYA_SPREADSHEET_BUILD=true mix deps.compile --force
Runtime Errors
Problem: Spreadsheet Reference Errors
Symptoms:
** (ArgumentError) argument error
Common Causes & Solutions:
Using invalid spreadsheet reference:
# Wrong - using a closed or invalid reference {:ok, spreadsheet} = UmyaSpreadsheet.new() # ... reference becomes invalid somehow ... UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "test") # Solution - always check if operations succeed case UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "test") do :ok -> :ok {:error, reason} -> Logger.error("Failed to set cell value: #{reason}") # Handle error appropriately end
Concurrent access to the same reference:
# Wrong - sharing reference between processes Task.async(fn -> UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "1") end) Task.async(fn -> UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A2", "2") end) # Solution - use separate spreadsheet instances Task.async(fn -> {:ok, s1} = UmyaSpreadsheet.new() UmyaSpreadsheet.set_cell_value(s1, "Sheet1", "A1", "1") end)
Problem: Sheet Not Found Errors
Symptoms:
{:error, "Sheet not found"}
Solutions:
Check sheet names:
# List all sheets first sheets = UmyaSpreadsheet.get_sheet_names(spreadsheet) IO.inspect(sheets) # ["Sheet1", "Sheet2", ...] # Use exact sheet name UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "value")
Handle missing sheets gracefully:
def safe_set_cell_value(spreadsheet, sheet_name, cell, value) do case UmyaSpreadsheet.set_cell_value(spreadsheet, sheet_name, cell, value) do :ok -> :ok {:error, "Sheet not found"} -> UmyaSpreadsheet.add_sheet(spreadsheet, sheet_name) UmyaSpreadsheet.set_cell_value(spreadsheet, sheet_name, cell, value) {:error, reason} -> {:error, reason} end end
Problem: Invalid Cell References
Symptoms:
{:error, "Invalid cell reference"}
Solutions:
Use valid Excel cell references:
# Valid formats UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "value") UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "Z100", "value") UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "AA1", "value") # Invalid formats (will fail) # UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "1A", "value") # UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A", "value")
Validate cell references:
def validate_cell_ref(cell_ref) do case Regex.match?(~r/^[A-Z]+[1-9]\d*$/, cell_ref) do true -> :ok false -> {:error, "Invalid cell reference format"} end end
Performance Issues
Problem: Slow File Operations
Symptoms:
- Long write times for large files
- High memory usage during operations
Solutions:
Use light writers for simple operations:
# For simple spreadsheets without complex formatting UmyaSpreadsheet.write_light(spreadsheet, "output.xlsx")
Use lazy reading for large files:
# For reading large files {:ok, spreadsheet} = UmyaSpreadsheet.lazy_read("large_file.xlsx")
Batch operations:
# Instead of individual cell operations for row <- 1..1000 do UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A#{row}", "value#{row}") end # Use bulk operations when available data = for row <- 1..1000, do: {"A#{row}", "value#{row}"} # Set multiple values in batch (if such function exists)
Problem: Memory Usage Growing
Symptoms:
- Increasing memory usage over time
- Out of memory errors with large files
Solutions:
Use streaming operations:
# Process data in chunks def process_large_file(file_path) do {:ok, spreadsheet} = UmyaSpreadsheet.lazy_read(file_path) # Process data in smaller chunks Enum.chunk_every(1..10000, 100) |> Enum.each(fn chunk -> process_chunk(spreadsheet, chunk) # Allow garbage collection :erlang.garbage_collect() end) end
Dispose of references when done:
def process_and_cleanup() do {:ok, spreadsheet} = UmyaSpreadsheet.new() try do # Do work with spreadsheet UmyaSpreadsheet.write(spreadsheet, "output.xlsx") after # Spreadsheet reference will be garbage collected # when it goes out of scope :ok end end
File Format Issues
Problem: Corrupted Output Files
Symptoms:
- Excel reports file corruption
- Unable to open generated files
Solutions:
Ensure proper file extensions:
# Use .xlsx for Excel files UmyaSpreadsheet.write(spreadsheet, "output.xlsx") # Not .xls (older format not supported)
Check file permissions:
def safe_write(spreadsheet, path) do case UmyaSpreadsheet.write(spreadsheet, path) do :ok -> :ok {:error, reason} -> Logger.error("Failed to write file #{path}: #{reason}") {:error, reason} end end
Validate data before writing:
def validate_and_write(spreadsheet, path) do # Check if spreadsheet has valid data case UmyaSpreadsheet.get_sheet_names(spreadsheet) do [] -> {:error, "No sheets in spreadsheet"} _sheets -> UmyaSpreadsheet.write(spreadsheet, path) end end
Problem: Encoding Issues
Symptoms:
- Special characters not displaying correctly
- UTF-8 encoding problems
Solutions:
Ensure UTF-8 encoding:
# When setting cell values with special characters UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "Café ñoño 中文")
Handle CSV encoding properly:
# When exporting to CSV UmyaSpreadsheet.to_csv(spreadsheet, "Sheet1", "output.csv")
Memory Issues
Problem: Out of Memory Errors
Symptoms:
** (SystemLimitError) a system limit has been reached
Solutions:
Process data in smaller chunks:
def process_large_dataset(data) do data |> Enum.chunk_every(1000) # Process 1000 rows at a time |> Enum.reduce({:ok, _} = UmyaSpreadsheet.new(), fn chunk, {:ok, spreadsheet} -> process_chunk(spreadsheet, chunk) {:ok, spreadsheet} end) end
Use memory-efficient patterns:
# Instead of keeping all data in memory def stream_to_excel(data_stream, output_path) do {:ok, spreadsheet} = UmyaSpreadsheet.new() data_stream |> Stream.with_index(1) |> Stream.each(fn {row_data, row_num} -> row_data |> Enum.with_index(1) |> Enum.each(fn {value, col_num} -> cell = "#{<<64 + col_num>>}#{row_num}" UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", cell, value) end) end) |> Stream.run() UmyaSpreadsheet.write(spreadsheet, output_path) end
Concurrency Issues
Problem: Race Conditions
Symptoms:
- Inconsistent results with concurrent operations
- Occasional crashes with multiple processes
Solutions:
Use separate spreadsheet instances:
# Good - each task has its own spreadsheet tasks = for i <- 1..10 do Task.async(fn -> {:ok, spreadsheet} = UmyaSpreadsheet.new() UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "Task #{i}") UmyaSpreadsheet.write(spreadsheet, "output_#{i}.xlsx") end) end Task.await_many(tasks)
Coordinate access with GenServer:
defmodule SpreadsheetManager do use GenServer def start_link(opts) do GenServer.start_link(__MODULE__, opts, name: __MODULE__) end def update_cell(sheet_name, cell, value) do GenServer.call(__MODULE__, {:update_cell, sheet_name, cell, value}) end def init(_opts) do {:ok, spreadsheet} = UmyaSpreadsheet.new() {:ok, %{spreadsheet: spreadsheet}} end def handle_call({:update_cell, sheet_name, cell, value}, _from, state) do result = UmyaSpreadsheet.set_cell_value(state.spreadsheet, sheet_name, cell, value) {:reply, result, state} end end
Platform-Specific Issues
macOS Issues
Problem: Code signing issues
# Solution: Allow unsigned binaries (development only)
sudo spctl --master-disable
Problem: Rosetta issues on Apple Silicon
# Solution: Use native ARM64 Rust
arch -arm64 brew install rust
export UMYA_SPREADSHEET_BUILD=true
mix deps.compile --force
Linux Issues
Problem: Missing system dependencies
# Solution: Install required packages
sudo apt-get update
sudo apt-get install build-essential pkg-config libssl-dev
Windows Issues
Problem: Visual Studio Build Tools not found
REM Solution: Install Visual Studio Build Tools
winget install Microsoft.VisualStudio.2022.BuildTools
Best Practices
1. Error Handling
Always handle errors appropriately:
def safe_spreadsheet_operation(spreadsheet, operation) do
case operation.(spreadsheet) do
:ok -> :ok
{:ok, result} -> {:ok, result}
{:error, reason} ->
Logger.error("Spreadsheet operation failed: #{reason}")
{:error, reason}
end
end
2. Resource Management
Create spreadsheets close to where they're used:
def generate_report(data) do
{:ok, spreadsheet} = UmyaSpreadsheet.new()
try do
populate_spreadsheet(spreadsheet, data)
UmyaSpreadsheet.write(spreadsheet, "report.xlsx")
rescue
error ->
Logger.error("Failed to generate report: #{inspect(error)}")
{:error, "Report generation failed"}
end
end
3. Performance Optimization
Use appropriate functions for your use case:
# For simple operations
UmyaSpreadsheet.write_light(spreadsheet, path)
# For large files
{:ok, spreadsheet} = UmyaSpreadsheet.lazy_read(path)
# For memory optimization
UmyaSpreadsheet.to_binary_xlsx(spreadsheet)
4. Data Validation
Validate inputs before processing:
def validate_cell_data(cell_ref, value) do
with :ok <- validate_cell_reference(cell_ref),
:ok <- validate_cell_value(value) do
:ok
else
{:error, reason} -> {:error, reason}
end
end
def validate_cell_reference(cell_ref) when is_binary(cell_ref) do
if Regex.match?(~r/^[A-Z]+[1-9]\d*$/, cell_ref) do
:ok
else
{:error, "Invalid cell reference format"}
end
end
def validate_cell_value(value) when is_binary(value) or is_number(value), do: :ok
def validate_cell_value(_), do: {:error, "Invalid cell value type"}
Debugging Tips
1. Enable Debug Logging
# In config/config.exs
config :logger, level: :debug
# In your code
require Logger
Logger.debug("Spreadsheet operation: #{inspect(operation_details)}")
2. Inspect Spreadsheet State
def debug_spreadsheet(spreadsheet) do
sheets = UmyaSpreadsheet.get_sheet_names(spreadsheet)
Logger.debug("Available sheets: #{inspect(sheets)}")
for sheet <- sheets do
Logger.debug("Sheet #{sheet} active: #{UmyaSpreadsheet.is_sheet_visible(spreadsheet, sheet)}")
end
end
3. Test with Minimal Examples
def minimal_test() do
{:ok, spreadsheet} = UmyaSpreadsheet.new()
:ok = UmyaSpreadsheet.set_cell_value(spreadsheet, "Sheet1", "A1", "test")
value = UmyaSpreadsheet.get_cell_value(spreadsheet, "Sheet1", "A1")
IO.puts("Cell A1 value: #{value}")
UmyaSpreadsheet.write(spreadsheet, "/tmp/test.xlsx")
end
4. Check System Resources
# Monitor memory usage
:observer.start()
# Check process memory
:erlang.memory()
# Monitor file handles
System.cmd("lsof", ["-p", "#{System.otp_release()}"])
Getting Help
If you encounter issues not covered in this guide:
- Check the GitHub Issues: umya_spreadsheet_ex issues
- Review the Documentation: HexDocs
- Check Rust Library Issues: umya-spreadsheet issues
- Create a Minimal Reproduction: Provide the smallest possible code that reproduces the issue
When reporting issues, include:
- Elixir and OTP versions
- Operating system and architecture
- UmyaSpreadsheet version
- Minimal code to reproduce the issue
- Full error messages and stack traces