or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client.mderrors.mdindex.mdpathio.mdserver.mdstreaming.md

errors.mddocs/

0

# Error Handling

1

2

Exception hierarchy for FTP operations including protocol errors, path validation, I/O errors, and connection issues. All exceptions inherit from AIOFTPException providing consistent error handling and detailed error information for debugging FTP operations.

3

4

## Capabilities

5

6

### Base Exception

7

8

Root exception class for all aioftp-related errors.

9

10

```python { .api }

11

class AIOFTPException(Exception):

12

"""

13

Base exception for all aioftp errors.

14

15

This is the root exception class that all other aioftp exceptions inherit from.

16

Catching this exception will catch all aioftp-specific errors.

17

"""

18

```

19

20

### Protocol Errors

21

22

Exceptions related to FTP protocol violations and unexpected server responses.

23

24

```python { .api }

25

class StatusCodeError(AIOFTPException):

26

"""

27

Raised when FTP server returns unexpected status code.

28

29

This exception is raised when the server returns a status code that doesn't

30

match what was expected for a particular FTP command. It includes detailed

31

information about both expected and received codes.

32

"""

33

34

expected_codes: tuple[Code, ...]

35

"""Status codes that were expected from the server."""

36

37

received_codes: tuple[Code, ...]

38

"""Status codes actually received from the server."""

39

40

info: Union[list[str], str]

41

"""Additional information from the server response."""

42

43

def __init__(expected_codes, received_codes, info):

44

"""

45

Initialize StatusCodeError.

46

47

Parameters:

48

- expected_codes: Codes that were expected

49

- received_codes: Codes actually received

50

- info: Server response information

51

"""

52

```

53

54

### Path Validation Errors

55

56

Exceptions for path-related validation and operations.

57

58

```python { .api }

59

class PathIsNotAbsolute(AIOFTPException):

60

"""

61

Raised when path is not absolute but should be.

62

63

Some operations require absolute paths. This exception is raised when

64

a relative path is provided where an absolute path is required.

65

"""

66

67

def __init__(path):

68

"""

69

Initialize PathIsNotAbsolute error.

70

71

Parameters:

72

- path: The invalid relative path that was provided

73

"""

74

75

class PathIOError(AIOFTPException):

76

"""

77

Universal exception for path I/O operations.

78

79

This exception wraps filesystem-related errors and provides additional

80

context about the operation that failed. It preserves the original

81

exception information for debugging.

82

"""

83

84

reason: Union[tuple, None]

85

"""Original exception information from the wrapped error."""

86

87

def __init__(reason):

88

"""

89

Initialize PathIOError.

90

91

Parameters:

92

- reason: Original exception info (usually from sys.exc_info())

93

"""

94

```

95

96

### Connection and Port Errors

97

98

Exceptions related to network connections and port availability.

99

100

```python { .api }

101

class NoAvailablePort(AIOFTPException, OSError):

102

"""

103

Raised when no data ports are available for FTP data connections.

104

105

This exception is raised when the server cannot find an available port

106

from the configured data port range for establishing data connections.

107

Inherits from both AIOFTPException and OSError for compatibility.

108

"""

109

110

def __init__(message="No available ports"):

111

"""

112

Initialize NoAvailablePort error.

113

114

Parameters:

115

- message: Error message describing the port availability issue

116

"""

117

```

118

119

## Usage Examples

120

121

### Basic Error Handling

122

123

```python

124

import aioftp

125

import asyncio

126

127

async def handle_basic_errors():

128

try:

129

async with aioftp.Client.context("ftp.example.com") as client:

130

await client.upload("local_file.txt", "remote_file.txt")

131

132

except aioftp.StatusCodeError as e:

133

print(f"FTP protocol error: {e}")

134

print(f"Expected: {e.expected_codes}, Got: {e.received_codes}")

135

print(f"Server message: {e.info}")

136

137

except aioftp.PathIOError as e:

138

print(f"File system error: {e}")

139

if e.reason:

140

print(f"Original error: {e.reason}")

141

142

except aioftp.AIOFTPException as e:

143

print(f"General FTP error: {e}")

144

145

except Exception as e:

146

print(f"Unexpected error: {e}")

147

148

asyncio.run(handle_basic_errors())

149

```

150

151

### Specific Error Types

152

153

```python

154

import aioftp

155

import asyncio

156

157

async def handle_specific_errors():

158

try:

159

async with aioftp.Client.context("ftp.example.com") as client:

160

# This might raise StatusCodeError if file doesn't exist

161

await client.download("nonexistent_file.txt", "local_file.txt")

162

163

except aioftp.StatusCodeError as e:

164

if "550" in str(e.received_codes):

165

print("File not found on server")

166

elif "426" in str(e.received_codes):

167

print("Connection closed during transfer")

168

else:

169

print(f"Other protocol error: {e}")

170

171

except aioftp.PathIsNotAbsolute as e:

172

print(f"Path must be absolute: {e}")

173

174

except aioftp.NoAvailablePort as e:

175

print(f"Server has no available data ports: {e}")

176

177

asyncio.run(handle_specific_errors())

178

```

179

180

### Server Error Handling

181

182

```python

183

import aioftp

184

import asyncio

185

from pathlib import Path

186

187

async def server_error_handling():

188

try:

189

users = [aioftp.User(

190

login="test",

191

password="test",

192

base_path=Path("/nonexistent/path") # This might cause issues

193

)]

194

195

server = aioftp.Server(users=users)

196

await server.run(host="localhost", port=21)

197

198

except aioftp.PathIOError as e:

199

print(f"Server path error: {e}")

200

print("Check that base paths exist and are accessible")

201

202

except aioftp.NoAvailablePort as e:

203

print(f"Port binding error: {e}")

204

print("Try a different port or check port availability")

205

206

except aioftp.AIOFTPException as e:

207

print(f"Server startup error: {e}")

208

209

asyncio.run(server_error_handling())

210

```

211

212

### Custom Error Handling with Retry Logic

213

214

```python

215

import aioftp

216

import asyncio

217

import logging

218

219

async def robust_ftp_operation():

220

"""Example with retry logic and comprehensive error handling."""

221

222

max_retries = 3

223

retry_delay = 1.0

224

225

for attempt in range(max_retries):

226

try:

227

async with aioftp.Client.context("ftp.example.com") as client:

228

await client.upload("important_file.txt", "backup.txt")

229

print("Upload successful!")

230

return

231

232

except aioftp.StatusCodeError as e:

233

if "550" in str(e.received_codes):

234

# Permission denied or file not found - don't retry

235

print(f"Permanent error: {e}")

236

break

237

elif "4" in str(e.received_codes)[0]:

238

# Temporary error (4xx codes) - retry

239

print(f"Temporary error (attempt {attempt + 1}): {e}")

240

if attempt < max_retries - 1:

241

await asyncio.sleep(retry_delay)

242

continue

243

244

except aioftp.PathIOError as e:

245

print(f"Local file error: {e}")

246

break # Don't retry file system errors

247

248

except (ConnectionError, OSError) as e:

249

# Network errors - retry

250

print(f"Network error (attempt {attempt + 1}): {e}")

251

if attempt < max_retries - 1:

252

await asyncio.sleep(retry_delay)

253

continue

254

255

except aioftp.AIOFTPException as e:

256

print(f"FTP error: {e}")

257

break

258

259

print("All retry attempts failed")

260

261

asyncio.run(robust_ftp_operation())

262

```

263

264

### Error Logging and Monitoring

265

266

```python

267

import aioftp

268

import asyncio

269

import logging

270

271

# Configure logging

272

logging.basicConfig(level=logging.INFO)

273

logger = logging.getLogger(__name__)

274

275

async def monitored_ftp_operation():

276

"""Example with comprehensive error logging."""

277

278

try:

279

async with aioftp.Client.context("ftp.example.com") as client:

280

# Log successful connection

281

logger.info("Connected to FTP server")

282

283

await client.upload("data.txt", "remote_data.txt")

284

logger.info("File uploaded successfully")

285

286

except aioftp.StatusCodeError as e:

287

logger.error(

288

"FTP protocol error: expected %s, got %s, info: %s",

289

e.expected_codes, e.received_codes, e.info

290

)

291

# Could send alert to monitoring system here

292

293

except aioftp.PathIOError as e:

294

logger.error("File system error: %s", e)

295

if e.reason:

296

logger.debug("Original exception: %s", e.reason)

297

298

except aioftp.NoAvailablePort as e:

299

logger.critical("No available ports for FTP data connection: %s", e)

300

# Critical infrastructure issue

301

302

except aioftp.AIOFTPException as e:

303

logger.error("General FTP error: %s", e)

304

305

except Exception as e:

306

logger.exception("Unexpected error in FTP operation")

307

308

asyncio.run(monitored_ftp_operation())

309

```

310

311

## Error Code Patterns

312

313

Common FTP status codes and their meanings:

314

315

- **1xx (Positive Preliminary)**: Command accepted, another command expected

316

- **2xx (Positive Completion)**: Command completed successfully

317

- **3xx (Positive Intermediate)**: Command accepted, more information needed

318

- **4xx (Transient Negative)**: Temporary failure, command may be retried

319

- **5xx (Permanent Negative)**: Permanent failure, command should not be retried

320

321

Common specific codes:

322

- **425**: Can't open data connection

323

- **426**: Connection closed; transfer aborted

324

- **450**: File unavailable (e.g., file busy)

325

- **451**: Local error in processing

326

- **550**: File unavailable (e.g., file not found, no access)

327

- **552**: Exceeded storage allocation

328

- **553**: File name not allowed

329

330

## Best Practices

331

332

1. **Always catch AIOFTPException** as a fallback for any aioftp-specific errors

333

2. **Check status codes** in StatusCodeError to determine if operations should be retried

334

3. **Log error details** including expected vs received codes for debugging

335

4. **Handle PathIOError separately** as it indicates local filesystem issues

336

5. **Use appropriate retry logic** for temporary errors (4xx codes)

337

6. **Don't retry permanent errors** (5xx codes) automatically