# FEX Core SDK - Troubleshooting Guide

This guide helps you resolve common issues when integrating with FEX Core SDK.

## Quick Diagnosis

| Symptom | Likely Cause | Solution |
|---------|--------------|----------|
| "DLL not found" | Missing DLL or dependencies | [DLL Loading Issues](#dll-loading-issues) |
| Error code -20 | Invalid license key | [License Key Problems](#license-key-problems) |
| Error code -4 | Unsupported image format | [Format-Specific Problems](#format-specific-problems) |
| Error code -6 | Cannot open image file | [Format-Specific Problems](#format-specific-problems) |
| Memory grows over time | Buffer not freed | [Memory/Performance Issues](#memoryperformance-issues) |
| Slow performance | Large image, wrong API | [Memory/Performance Issues](#memoryperformance-issues) |

---

## DLL Loading Issues

### "DLL not found" Error

**Symptoms:**
- Python: `FileNotFoundError: Could not find module 'FEX.Core.dll'`
- C#: `DllNotFoundException`
- C++: `LoadLibrary` returns NULL

**Root Causes:**

1. **DLL not in expected location**
2. **Missing dependencies**
3. **Architecture mismatch (32-bit vs 64-bit)**

**Resolution Steps:**

**Step 1: Verify DLL location**

```
SDK Directory/
├── bin/
│   └── Win64/
│       ├── FEX.Core.dll          ← Main DLL
│       └── libcrypto-1_1-x64.dll ← Required dependency
```

**Step 2: Check the exact path in your code**

```python
import os
dll_path = os.path.join("bin", "Win64", "FEX.Core.dll")
print(f"Looking for DLL at: {os.path.abspath(dll_path)}")
print(f"Exists: {os.path.exists(dll_path)}")
```

**Step 3: Verify dependencies exist**

The following files must be in the same directory as `FEX.Core.dll`:

| File | Required | Purpose |
|------|----------|---------|
| `FEX.Core.dll` | Yes | Main SDK DLL |
| `libcrypto-1_1-x64.dll` | Yes | OpenSSL cryptography |
| `sk4d.dll` | Optional | Skia graphics (if SKIA enabled) |

### Missing Dependency Errors

**Symptoms:**
- "The specified module could not be found"
- "A DLL initialization routine failed"
- Application crashes on DLL load

**Resolution:**

1. **Copy all DLLs together:**
   ```
   bin/Win64/
   ├── FEX.Core.dll
   └── libcrypto-1_1-x64.dll  ← Must be here!
   ```

2. **Use Dependency Walker to diagnose:**
   - Download from https://dependencywalker.com/
   - Open `FEX.Core.dll`
   - Look for missing DLLs (marked with "?" icon)

3. **Add DLL directory to PATH (Python):**
   ```python
   import os
   dll_dir = os.path.join(os.path.dirname(__file__), "..", "bin", "Win64")
   os.environ["PATH"] = dll_dir + os.pathsep + os.environ["PATH"]
   ```

### Architecture Mismatch (32-bit vs 64-bit)

**Symptoms:**
- "Bad EXE format" error
- "is not a valid Win32 application"
- `OSError: [WinError 193]`

**Root Cause:**
FEX.Core.dll is 64-bit only. Using 32-bit Python/runtime causes this error.

**Resolution:**

```python
import platform
import sys

# Check Python architecture
arch = platform.architecture()[0]
if arch != "64bit":
    print(f"ERROR: 64-bit Python required. Current: {arch}")
    print(f"Python path: {sys.executable}")
    sys.exit(1)
```

**Fix:** Install 64-bit Python from python.org.

---

## License Key Problems

For installation steps and code samples, see **[License Keys](license-keys.md)**.

### Invalid Key Error (Code -20)

**Symptoms:**
- `InitLibrary()` returns `RESULT_INVALIDKEY` (-20)
- `OpenImage()` returns -20 (because the library was never successfully initialised)

**Common causes:**

1. **`FEX_LICENSE_KEY` not set** in the current shell, or the key was passed
   to a different process.
2. **Whitespace or line-wrap** introduced when copying the key — the value
   must be a single contiguous string.
3. **Wrong key string** — the value isn't the GetData-issued `FEX2-…` key.
4. **Expired key** — the key has passed its expiry date.
5. **Clock skew** — the host system clock is far behind or ahead of UTC,
   which can make a valid key look expired or not-yet-valid.
6. **Wrong working directory (Windows)** — the host process's CWD must be
   the same directory as `FEX.Core.dll` when `InitLibrary` is called. The
   bundled examples handle this automatically; custom integrations that
   load the DLL from another directory should `chdir` to the DLL's
   directory around the `InitLibrary` call.

**Resolution steps:**

1. **Confirm the variable is visible to your process.**

   ```powershell
   # Windows (PowerShell)
   $env:FEX_LICENSE_KEY.Substring(0, 5)   # should print 'FEX2-'
   ```

   ```bash
   # Linux / macOS
   echo "${FEX_LICENSE_KEY:0:5}"          # should print 'FEX2-'
   ```

2. **Re-copy the key from your sales email** (or secret manager). Make sure
   no newline, tab, or trailing space was included.

3. **Check the host clock** is set to current UTC (within a few minutes).

4. **Try the bundled `FexViewer info` command** with your key — it gives a
   clear pass/fail without your integration code in the way.

5. **Contact `support@getdata.com`** if the key still fails. Include:

   - The first 4 and last 4 characters of the key (never the full string).
   - The exact error code returned (`-20`, `-21`, etc.).
   - SDK version (output of `FexViewer info` or `GetVersionAsJSON`).
   - Operating system and architecture.

### Expired Key

**Symptoms:**
- A key that previously worked now returns `-20`.
- Evaluation period has ended.

**Resolution:**
- Contact `sales@getdata.com` for renewal.
- Check your email for renewal notices.

---

## Memory/Performance Issues

### Memory Leaks

**Symptoms:**
- Memory usage grows continuously
- Application slows down over time
- Eventually crashes with out-of-memory

**Root Cause:**
Not calling `FreeAllocatedBuffer()` after V2 API calls.

**Detection:**

```python
import tracemalloc

tracemalloc.start()

# Your code here
for i in range(100):
    buffer = ctypes.c_void_p()
    size = ctypes.c_uint32()
    dll.GetVersionAsJSON(ctypes.byref(buffer), ctypes.byref(size))
    # MISSING: dll.FreeAllocatedBuffer(buffer)

current, peak = tracemalloc.get_traced_memory()
print(f"Memory: {current / 1024 / 1024:.1f} MB")
tracemalloc.stop()
```

**Resolution:**

Always use try/finally:

```python
buffer = ctypes.c_void_p()
size = ctypes.c_uint32()
result = dll.SomeFunction_V2(ctypes.byref(buffer), ctypes.byref(size))

if result == 0:
    try:
        # Use buffer
        data = ctypes.string_at(buffer, size.value)
    finally:
        dll.FreeAllocatedBuffer(buffer)  # ALWAYS FREE
```

### Large Image Performance

**Symptoms:**
- Opening large images takes minutes
- File listing is very slow
- High memory usage

**Resolution:**

1. **Use V3 API for selective field extraction:**
   ```python
   # Instead of getting all fields
   dll.GetFileSystemRecords_V2(...)

   # Get only what you need
   fields = "Name,Size,Modified"
   dll.GetFileSystemRecordsCustom(..., fields.encode(), ...)
   ```

2. **Process in batches:**
   ```python
   # Don't load all files into memory at once
   batch_size = 1000
   for offset in range(0, total_files, batch_size):
       batch = files[offset:offset + batch_size]
       process(batch)
   ```

3. **Close images when done:**
   ```python
   # Don't leave images open
   image_id = dll.ImageOpen(path, key)
   try:
       # ... work with image ...
   finally:
       dll.ImageClose(image_id)
   ```

### Performance Optimization Tips

| Issue | Solution |
|-------|----------|
| Slow image open | Use SSD, check image isn't corrupted |
| Slow file listing | Use V3 API with minimal fields |
| High memory | Process in batches, free buffers |
| Repeated opens | Cache image handle, open once |

---

## Format-Specific Problems

### Error -4: Image Not Supported

**Symptoms:**
- `ImageOpen()` returns -4
- Certain image files won't open

**Root Causes:**

1. **Unsupported format**
2. **Corrupted image header**
3. **Wrong file extension**

**Supported Formats:**

| Format | Extensions | Notes |
|--------|------------|-------|
| DD/RAW | .dd, .raw, .img, .001 | Uncompressed disk image |
| E01 | .E01, .E02, ... | EnCase format |
| L01 | .L01, .L02, ... | Logical evidence |
| AFF4 | .aff4 | If enabled in build |

**Resolution:**

1. **Verify file format:**
   ```python
   import os

   path = "evidence/disk.img"
   ext = os.path.splitext(path)[1].lower()

   supported = {'.dd', '.raw', '.img', '.001', '.e01', '.l01', '.aff4'}
   if ext not in supported:
       print(f"Extension '{ext}' may not be supported")
   ```

2. **Check file header:**
   ```python
   with open(path, 'rb') as f:
       header = f.read(16)
       print(f"Header bytes: {header.hex()}")

   # E01 should start with: 45 56 46 09 0D 0A FF 00
   # (EVF signature)
   ```

3. **Try opening as raw:**
   If format detection fails, rename to `.dd` and try as raw image.

### Error -6: Could Not Open Image

**Symptoms:**
- `ImageOpen()` returns -6
- File exists but can't be opened

**Root Causes:**

1. **File permissions**
2. **File locked by another process**
3. **Path encoding issues**
4. **Network path issues**

**Resolution:**

1. **Check file permissions:**
   ```python
   import os

   path = "evidence/disk.E01"
   if not os.path.exists(path):
       print("File not found")
   elif not os.access(path, os.R_OK):
       print("No read permission")
   else:
       print("File accessible")
   ```

2. **Check if file is locked:**
   - Close other applications that might have the file open
   - EnCase, FTK, or other forensic tools may lock files

3. **Use correct path encoding:**
   ```python
   # For non-ASCII paths
   path = "evidence/案件.E01"
   encoded_path = path.encode('utf-8')
   result = dll.ImageOpen(encoded_path, key)
   ```

4. **Avoid network paths if possible:**
   - Copy image to local drive for best performance
   - UNC paths may have permission issues

### Filesystem-Specific Issues

**NTFS Issues:**
- Alternate data streams may not appear in simple listings
- Very deep paths (>260 chars) may fail on older Windows

**FAT32 Issues:**
- 4GB file size limit in original filesystem
- Timestamps have 2-second resolution

**EXT4 Issues:**
- Extended attributes may require additional API calls
- Some sparse file handling limitations

---

## Debugging Techniques

### Enable Verbose Output

```python
import sys

def debug_print(msg):
    print(f"[DEBUG] {msg}", file=sys.stderr)

# Add debug output to your workflow
debug_print(f"Opening image: {path}")
result = dll.ImageOpen(path.encode(), key.encode())
debug_print(f"ImageOpen result: {result}")
```

### Check Error Codes

```python
ERROR_CODES = {
    0: "OK - Success",
    -1: "General error",
    -2: "Buffer too small (V1 API)",
    -3: "File not found",
    -4: "Image format not supported",
    -5: "Image ID not found",
    -6: "Could not open image",
    -20: "Invalid license key"
}

def describe_error(code):
    return ERROR_CODES.get(code, f"Unknown error: {code}")
```

### Diagnostic Tools

| Tool | Platform | Purpose |
|------|----------|---------|
| **Dependency Walker** | Windows | Find missing DLLs |
| **Process Monitor** | Windows | Track file access |
| **ldd** | Linux | Check shared library deps |
| **strace** | Linux | Trace system calls |

### Minimal Test Case

When reporting issues, create a minimal reproduction:

```python
#!/usr/bin/env python3
"""Minimal FEX Core test case"""
import ctypes
import os
import sys

# Configuration
DLL_PATH = "bin/Win64/FEX.Core.dll"
IMAGE_PATH = "sample-data/sample-image.dd"
LICENSE_KEY = "YOUR_KEY"

print(f"Python: {sys.version}")
print(f"Platform: {sys.platform}")
print(f"DLL exists: {os.path.exists(DLL_PATH)}")
print(f"Image exists: {os.path.exists(IMAGE_PATH)}")

try:
    dll = ctypes.CDLL(DLL_PATH)
    print("DLL loaded successfully")

    dll.ImageOpen.argtypes = [ctypes.c_char_p, ctypes.c_char_p]
    dll.ImageOpen.restype = ctypes.c_int

    result = dll.ImageOpen(
        IMAGE_PATH.encode(),
        LICENSE_KEY.encode()
    )
    print(f"ImageOpen result: {result}")

except Exception as e:
    print(f"Error: {type(e).__name__}: {e}")
```

---

## Support Escalation

### Self-Service Resources

1. **Documentation** - Check this guide and API references
2. **Sample Code** - Review working examples in `examples/` folder
3. **Error Codes** - See [Error Codes Reference](api/error-codes.md)

### When to Contact Support

Contact support when:
- Documentation doesn't resolve the issue
- You've followed all troubleshooting steps
- You have a reproducible test case
- License/activation issues

### How to Contact Support

**Email:** support@getdata.com

**Include in your report:**

1. **SDK Version:** (e.g., v1.0.0)
2. **Operating System:** (e.g., Windows 11 x64)
3. **Programming Language:** (e.g., Python 3.14)
4. **Error Code/Message:** (exact text)
5. **Steps to Reproduce:** (minimal test case)
6. **Image Format:** (e.g., E01, DD)
7. **Log Output:** (if available)

**Example support request:**

```
Subject: Error -6 opening E01 image

SDK Version: 1.0.0
OS: Windows 11 Pro x64
Language: Python 3.14.0

Problem: ImageOpen returns -6 for specific E01 file

Steps:
1. Downloaded SDK, extracted to C:\FEX-Core-SDK
2. Ran sample: FexViewer.exe info --image sample-image.dd
3. Sample works with sample-image.dd
4. Fails with my E01 file (attached test case)

Error output:
[Attach minimal test case and sanitized output]
```

### Response Times

| Priority | Response Target |
|----------|----------------|
| Trial users | 2-3 business days |
| Licensed customers | 1 business day |
| Critical production | Same business day |

---

**[Back to Documentation Index](index.md)**
