Coverage for /usr/local/lib/python3.12/site-packages/prefect/exceptions.py: 57%

130 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-12-05 13:38 +0000

1""" 

2Prefect-specific exceptions. 

3""" 

4 

5import inspect 1a

6import traceback 1a

7from collections.abc import Iterable 1a

8from types import ModuleType, TracebackType 1a

9from typing import TYPE_CHECKING, Any, Callable, Optional 1a

10 

11from httpx import HTTPStatusError 1a

12from pydantic import ValidationError 1a

13from typing_extensions import Self 1a

14 

15if TYPE_CHECKING: 15 ↛ 16line 15 didn't jump to line 16 because the condition on line 15 was never true1a

16 from prefect.states import State 

17 

18 

19def _trim_traceback( 1a

20 tb: TracebackType | None, remove_modules: Iterable[ModuleType] 

21) -> TracebackType | None: 

22 """ 

23 Utility to remove frames from specific modules from a traceback. 

24 

25 Only frames from the front of the traceback are removed. Once a traceback frame 

26 is reached that does not originate from `remove_modules`, it is returned. 

27 

28 Args: 

29 tb: The traceback to trim. 

30 remove_modules: An iterable of module objects to remove. 

31 

32 Returns: 

33 A traceback, or `None` if all traceback frames originate from an excluded module 

34 

35 """ 

36 strip_paths = [ 

37 module.__file__ for module in remove_modules if module.__file__ is not None 

38 ] 

39 while tb and any( 

40 module_path in str(tb.tb_frame.f_globals.get("__file__", "")) 

41 for module_path in strip_paths 

42 ): 

43 tb = tb.tb_next 

44 

45 return tb 

46 

47 

48def exception_traceback(exc: Exception) -> str: 1a

49 """ 

50 Convert an exception to a printable string with a traceback 

51 """ 

52 tb = traceback.TracebackException.from_exception(exc) 

53 return "".join(list(tb.format())) 

54 

55 

56class PrefectException(Exception): 1a

57 """ 

58 Base exception type for Prefect errors. 

59 """ 

60 

61 

62class CrashedRun(PrefectException): 1a

63 """ 

64 Raised when the result from a crashed run is retrieved. 

65 

66 This occurs when a string is attached to the state instead of an exception or if 

67 the state's data is null. 

68 """ 

69 

70 

71class FailedRun(PrefectException): 1a

72 """ 

73 Raised when the result from a failed run is retrieved and an exception is not 

74 attached. 

75 

76 This occurs when a string is attached to the state instead of an exception or if 

77 the state's data is null. 

78 """ 

79 

80 

81class CancelledRun(PrefectException): 1a

82 """ 

83 Raised when the result from a cancelled run is retrieved and an exception 

84 is not attached. 

85 

86 This occurs when a string is attached to the state instead of an exception 

87 or if the state's data is null. 

88 """ 

89 

90 

91class PausedRun(PrefectException): 1a

92 """ 

93 Raised when the result from a paused run is retrieved. 

94 """ 

95 

96 def __init__( 1a

97 self, *args: Any, state: Optional["State[Any]"] = None, **kwargs: Any 

98 ) -> None: 

99 super().__init__(*args, **kwargs) 

100 self.state = state 

101 

102 

103class UnfinishedRun(PrefectException): 1a

104 """ 

105 Raised when the result from a run that is not finished is retrieved. 

106 

107 For example, if a run is in a SCHEDULED, PENDING, CANCELLING, or RUNNING state. 

108 """ 

109 

110 

111class MissingFlowError(PrefectException): 1a

112 """ 

113 Raised when a given flow name is not found in the expected script. 

114 """ 

115 

116 

117class UnspecifiedFlowError(PrefectException): 1a

118 """ 

119 Raised when multiple flows are found in the expected script and no name is given. 

120 """ 

121 

122 

123class MissingResult(PrefectException): 1a

124 """ 

125 Raised when a result is missing from a state; often when result persistence is 

126 disabled and the state is retrieved from the API. 

127 """ 

128 

129 

130class ScriptError(PrefectException): 1a

131 """ 

132 Raised when a script errors during evaluation while attempting to load data 

133 """ 

134 

135 def __init__( 1a

136 self, 

137 user_exc: Exception, 

138 path: str, 

139 ) -> None: 

140 import prefect.utilities.importtools 

141 

142 message = f"Script at {str(path)!r} encountered an exception: {user_exc!r}" 

143 super().__init__(message) 

144 self.user_exc = user_exc 

145 

146 # Strip script run information from the traceback 

147 self.user_exc.__traceback__ = _trim_traceback( 

148 self.user_exc.__traceback__, 

149 remove_modules=[prefect.utilities.importtools], 

150 ) 

151 

152 

153class ParameterTypeError(PrefectException): 1a

154 """ 

155 Raised when a parameter does not pass Pydantic type validation. 

156 """ 

157 

158 def __init__(self, msg: str): 1a

159 super().__init__(msg) 

160 

161 @classmethod 1a

162 def from_validation_error(cls, exc: ValidationError) -> Self: 1a

163 bad_params = [ 

164 f"{'.'.join(str(item) for item in err['loc'])}: {err['msg']}" 

165 for err in exc.errors() 

166 ] 

167 msg = "Flow run received invalid parameters:\n - " + "\n - ".join(bad_params) 

168 return cls(msg) 

169 

170 

171class ParameterBindError(TypeError, PrefectException): 1a

172 """ 

173 Raised when args and kwargs cannot be converted to parameters. 

174 """ 

175 

176 def __init__(self, msg: str): 1a

177 super().__init__(msg) 

178 

179 @classmethod 1a

180 def from_bind_failure( 1a

181 cls, 

182 fn: Callable[..., Any], 

183 exc: TypeError, 

184 call_args: tuple[Any, ...], 

185 call_kwargs: dict[str, Any], 

186 ) -> Self: 

187 fn_signature = str(inspect.signature(fn)).strip("()") 

188 

189 base = f"Error binding parameters for function '{fn.__name__}': {exc}" 

190 signature = f"Function '{fn.__name__}' has signature '{fn_signature}'" 

191 received = f"received args: {call_args} and kwargs: {list(call_kwargs.keys())}" 

192 msg = f"{base}.\n{signature} but {received}." 

193 return cls(msg) 

194 

195 

196class SignatureMismatchError(PrefectException, TypeError): 1a

197 """Raised when parameters passed to a function do not match its signature.""" 

198 

199 def __init__(self, msg: str): 1a

200 super().__init__(msg) 

201 

202 @classmethod 1a

203 def from_bad_params( 1a

204 cls, expected_params: list[str], provided_params: list[str] 

205 ) -> Self: 

206 msg = ( 

207 f"Function expects parameters {expected_params} but was provided with" 

208 f" parameters {provided_params}" 

209 ) 

210 return cls(msg) 

211 

212 

213class ObjectNotFound(PrefectException): 1a

214 """ 

215 Raised when the client receives a 404 (not found) from the API. 

216 """ 

217 

218 def __init__( 1a

219 self, 

220 http_exc: Exception, 

221 help_message: Optional[str] = None, 

222 *args: Any, 

223 **kwargs: Any, 

224 ) -> None: 

225 self.http_exc = http_exc 

226 self.help_message = help_message 

227 super().__init__(help_message, *args, **kwargs) 

228 

229 def __str__(self) -> str: 1a

230 return self.help_message or super().__str__() 

231 

232 

233class ObjectAlreadyExists(PrefectException): 1a

234 """ 

235 Raised when the client receives a 409 (conflict) from the API. 

236 """ 

237 

238 def __init__(self, http_exc: Exception, *args: Any, **kwargs: Any) -> None: 1a

239 self.http_exc = http_exc 

240 super().__init__(*args, **kwargs) 

241 

242 

243class ObjectLimitReached(PrefectException): 1a

244 """ 

245 Raised when the client receives a 403 (forbidden) from the API due to reaching an object limit (e.g. maximum number of deployments). 

246 """ 

247 

248 def __init__(self, http_exc: Exception, *args: Any, **kwargs: Any) -> None: 1a

249 self.http_exc = http_exc 

250 super().__init__(*args, **kwargs) 

251 

252 

253class ObjectUnsupported(PrefectException): 1a

254 """ 

255 Raised when the client receives a 403 (forbidden) from the API due to an unsupported object (i.e. requires a specific Prefect Cloud tier). 

256 """ 

257 

258 def __init__(self, http_exc: Exception, *args: Any, **kwargs: Any) -> None: 1a

259 self.http_exc = http_exc 

260 super().__init__(*args, **kwargs) 

261 

262 

263class UpstreamTaskError(PrefectException): 1a

264 """ 

265 Raised when a task relies on the result of another task but that task is not 

266 'COMPLETE' 

267 """ 

268 

269 

270class MissingContextError(PrefectException, RuntimeError): 1a

271 """ 

272 Raised when a method is called that requires a task or flow run context to be 

273 active but one cannot be found. 

274 """ 

275 

276 

277class MissingProfileError(PrefectException, ValueError): 1a

278 """ 

279 Raised when a profile name does not exist. 

280 """ 

281 

282 

283class ReservedArgumentError(PrefectException, TypeError): 1a

284 """ 

285 Raised when a function used with Prefect has an argument with a name that is 

286 reserved for a Prefect feature 

287 """ 

288 

289 

290class InvalidNameError(PrefectException, ValueError): 1a

291 """ 

292 Raised when a name contains characters that are not permitted. 

293 """ 

294 

295 

296class PrefectSignal(BaseException): 1a

297 """ 

298 Base type for signal-like exceptions that should never be caught by users. 

299 """ 

300 

301 

302class Abort(PrefectSignal): 1a

303 """ 

304 Raised when the API sends an 'ABORT' instruction during state proposal. 

305 

306 Indicates that the run should exit immediately. 

307 """ 

308 

309 

310class Pause(PrefectSignal): 1a

311 """ 

312 Raised when a flow run is PAUSED and needs to exit for resubmission. 

313 """ 

314 

315 def __init__( 1a

316 self, *args: Any, state: Optional["State[Any]"] = None, **kwargs: Any 

317 ) -> None: 

318 super().__init__(*args, **kwargs) 

319 self.state = state 

320 

321 

322class ExternalSignal(BaseException): 1a

323 """ 

324 Base type for external signal-like exceptions that should never be caught by users. 

325 """ 

326 

327 

328class TerminationSignal(ExternalSignal): 1a

329 """ 

330 Raised when a flow run receives a termination signal. 

331 """ 

332 

333 def __init__(self, signal: int): 1a

334 self.signal = signal 

335 

336 

337class PrefectHTTPStatusError(HTTPStatusError): 1a

338 """ 

339 Raised when client receives a `Response` that contains an HTTPStatusError. 

340 

341 Used to include API error details in the error messages that the client provides users. 

342 """ 

343 

344 @classmethod 1a

345 def from_httpx_error(cls: type[Self], httpx_error: HTTPStatusError) -> Self: 1a

346 """ 

347 Generate a `PrefectHTTPStatusError` from an `httpx.HTTPStatusError`. 

348 """ 

349 try: 

350 details = httpx_error.response.json() 

351 except Exception: 

352 details = None 

353 

354 error_message, *more_info = str(httpx_error).split("\n") 

355 

356 if details: 

357 message_components = [error_message, f"Response: {details}", *more_info] 

358 else: 

359 message_components = [error_message, *more_info] 

360 

361 new_message = "\n".join(message_components) 

362 

363 return cls( 

364 new_message, request=httpx_error.request, response=httpx_error.response 

365 ) 

366 

367 

368class MappingLengthMismatch(PrefectException): 1a

369 """ 

370 Raised when attempting to call Task.map with arguments of different lengths. 

371 """ 

372 

373 

374class MappingMissingIterable(PrefectException): 1a

375 """ 

376 Raised when attempting to call Task.map with all static arguments 

377 """ 

378 

379 

380class BlockMissingCapabilities(PrefectException): 1a

381 """ 

382 Raised when a block does not have required capabilities for a given operation. 

383 """ 

384 

385 

386class ProtectedBlockError(PrefectException): 1a

387 """ 

388 Raised when an operation is prevented due to block protection. 

389 """ 

390 

391 

392class InvalidRepositoryURLError(PrefectException): 1a

393 """Raised when an incorrect URL is provided to a GitHub filesystem block.""" 

394 

395 

396class InfrastructureError(PrefectException): 1a

397 """ 

398 A base class for exceptions related to infrastructure blocks 

399 """ 

400 

401 

402class InfrastructureNotFound(PrefectException): 1a

403 """ 

404 Raised when infrastructure is missing, likely because it has exited or been 

405 deleted. 

406 """ 

407 

408 

409class InfrastructureNotAvailable(PrefectException): 1a

410 """ 

411 Raised when infrastructure is not accessible from the current machine. For example, 

412 if a process was spawned on another machine it cannot be managed. 

413 """ 

414 

415 

416class NotPausedError(PrefectException): 1a

417 """Raised when attempting to unpause a run that isn't paused.""" 

418 

419 

420class FlowPauseTimeout(PrefectException): 1a

421 """Raised when a flow pause times out""" 

422 

423 

424class FlowRunWaitTimeout(PrefectException): 1a

425 """Raised when a flow run takes longer than a given timeout""" 

426 

427 

428class PrefectImportError(ImportError): 1a

429 """ 

430 An error raised when a Prefect object cannot be imported due to a move or removal. 

431 """ 

432 

433 def __init__(self, message: str) -> None: 1a

434 super().__init__(message) 

435 

436 

437class SerializationError(PrefectException): 1a

438 """ 

439 Raised when an object cannot be serialized. 

440 """ 

441 

442 

443class ConfigurationError(PrefectException): 1a

444 """ 

445 Raised when a configuration is invalid. 

446 """ 

447 

448 

449class ProfileSettingsValidationError(PrefectException): 1a

450 """ 

451 Raised when a profile settings are invalid. 

452 """ 

453 

454 def __init__(self, errors: list[tuple[Any, ValidationError]]) -> None: 1a

455 self.errors = errors 

456 

457 

458class HashError(PrefectException): 1a

459 """Raised when hashing objects fails"""