{"record":{"id":"f4538ac69d3051fa","repo":"microsoft/semantic-kernel","slug":"failed-to-get-the-weather","errorCode":null,"errorMessage":"Failed to get the weather","messagePattern":"Failed to get the weather","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"info","filePath":"python/samples/concepts/filtering/retry_with_filters.py","lineNumber":45,"sourceCode":"\n\nclass WeatherPlugin:\n    MAX_FAILURES = 2\n\n    def __init__(self):\n        self._invocation_count = 0\n\n    @kernel_function(name=\"GetWeather\", description=\"Get the weather of the day at the current location.\")\n    def get_weather(self) -> str:\n        \"\"\"Get the weather of the day at the current location.\n\n        Simulates a call to an external service to get the weather.\n        This function is designed to fail a certain number of times before succeeding.\n        \"\"\"\n        if self._invocation_count < self.MAX_FAILURES:\n            self._invocation_count += 1\n            print(f\"Number of attempts: {self._invocation_count}\")\n            raise Exception(\"Failed to get the weather\")\n\n        return \"Sunny\"\n\n\nasync def retry_filter(\n    context: FunctionInvocationContext,\n    next: Callable[[FunctionInvocationContext], Awaitable[None]],\n) -> None:\n    \"\"\"A filter that retries the function invocation if it fails.\n\n    The filter uses a binary exponential backoff strategy to retry the function invocation.\n    \"\"\"\n    for i in range(MAX_RETRIES):\n        try:\n            await next(context)\n            return\n        except Exception as e:\n            logger.warning(f\"Failed to execute the function: {e}\")","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/samples/concepts/filtering/retry_with_filters.py#L27-L63","documentation":"Exception raised deliberately by the sample WeatherPlugin.get_weather for its first MAX_FAILURES invocations, to simulate a flaky external service so the accompanying retry_filter can demonstrate exponential backoff. Once _invocation_count reaches MAX_FAILURES, it returns 'Sunny' instead. It is intentional simulated failure, not a real error path.","triggerScenarios":"Invoking the WeatherPlugin.GetWeather kernel function while _invocation_count < MAX_FAILURES. Each such call increments the counter, prints the attempt number, and raises Exception('Failed to get the weather').","commonSituations":"Running the retry_with_filters sample; the first one or two calls always raise by design. If you remove or disable the retry_filter, this exception will propagate to the caller instead of being retried.","solutions":["Keep the retry_filter registered (kernel.add_filter(FilterTypes.FUNCTION_INVOCATION, retry_filter)) so the simulated failures are retried until success.","Lower MAX_FAILURES to 0 to make get_weather succeed immediately when you no longer want the simulated flakiness.","Catch the Exception at the call site if you intentionally want to observe the failure.","Replace the simulated Exception with a realistic transient exception type if adapting the sample to a real service."],"exampleFix":"# before - always fails MAX_FAILURES times\nclass WeatherPlugin:\n    MAX_FAILURES = 3\n    def get_weather(self):\n        if self._invocation_count < self.MAX_FAILURES:\n            self._invocation_count += 1\n            raise Exception(\"Failed to get the weather\")\n        return \"Sunny\"\n# after - disable simulated failure for real use\nclass WeatherPlugin:\n    MAX_FAILURES = 0\n    def get_weather(self):\n        return \"Sunny\"","handlingStrategy":"retry","validationCode":"# If you do NOT want simulated failure, set MAX_FAILURES = 0 before invoking.\nplugin = WeatherPlugin()\nplugin.MAX_FAILURES = 0   # disables simulated flakiness\n# otherwise ensure the retry_filter is registered so failures are retried","typeGuard":"def will_succeed_now(plugin) -> bool:\n    return plugin._invocation_count >= getattr(plugin, \"MAX_FAILURES\", 0)","tryCatchPattern":"# Mirror the sample's retry_filter at your own call site if you drop the filter.\nfor attempt in range(MAX_RETRIES):\n    try:\n        result = await kernel.invoke(weather_func)\n        break\n    except Exception as e:\n        await asyncio.sleep(2 ** attempt)\nelse:\n    raise","preventionTips":["Keep the retry_filter registered while MAX_FAILURES > 0.","Set MAX_FAILURES = 0 when adapting the sample to a real, reliable service.","Replace the generic Exception with a realistic transient exception type for production code."],"tags":["python","sample","filters","retry","simulation"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}