Notify user when Duo Code Review fails to post review
Background
In !165761 (merged), Duo Code Review was executed but failed to post a review.
Looking at the logs (internal), it was failing because:
unexpected character (after ) at line 1, column 3 [parse.c:804] in '{ legacy_id: legacy_id } }\n = link_to \"##{id}\", { data: { line_number: line_number } } do\n = line_number\n- else\n %td \n```\n\nThis suggestion improves the code by explicitly specifying the link text and adding a non-breaking space in the empty cell for better accessibility and consistent rendering."}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":563,"output_tokens":219}}
Backtrace
lib/gitlab/json.rb:107:in `rescue in adapter_load', lib/gitlab/json.rb:102:in `adapter_load', lib/gitlab/json.rb:28:in `parse', ee/lib/gitlab/llm/anthropic/client.rb:201:in `block in parse_sse_events', ee/lib/gitlab/llm/anthropic/client.rb:201:in `map', ee/lib/gitlab/llm/anthropic/client.rb:201:in `parse_sse_events', ee/lib/gitlab/llm/anthropic/client.rb:131:in `block in perform_messages_request', gems/gitlab-http/lib/gitlab/http_v2/client.rb:102:in `block in sync_perform_request', httparty (0.21.0) lib/httparty/request.rb:163:in `block (2 levels) in perform', net-protocol (0.1.3) lib/net/protocol.rb:498:in `call_block', net-protocol (0.1.3) lib/net/protocol.rb:489:in `<<', net-http (0.4.1) lib/net/http/response.rb:702:in `block (2 levels) in inflate_adapter', net-http (0.4.1) lib/net/http/response.rb:700:in `inflate', net-http (0.4.1) lib/net/http/response.rb:700:in `block in inflate_adapter', net-protocol (0.1.3) lib/net/protocol.rb:498:in `call_block', net-protocol (0.1.3) lib/net/protocol.rb:489:in `<<', net-protocol (0.1.3) lib/net/protocol.rb:165:in `read', net-http (0.4.1) lib/net/http/response.rb:723:in `read', net-http (0.4.1) lib/net/http/response.rb:631:in `read_chunked', net-http (0.4.1) lib/net/http/response.rb:595:in `block in read_body_0', net-http (0.4.1) lib/net/http/response.rb:570:in `inflater', net-http (0.4.1) lib/net/http/response.rb:593:in `read_body_0', net-http (0.4.1) lib/net/http/response.rb:363:in `read_body', httparty (0.21.0) lib/httparty/request.rb:160:in `block in perform', net-http (0.4.1) lib/net/http.rb:2353:in `block in transport_request', net-http (0.4.1) lib/net/http/response.rb:320:in `reading_body', net-http (0.4.1) lib/net/http.rb:2352:in `transport_request', net-http (0.4.1) lib/net/http.rb:2306:in `request', gitlab-labkit (0.36.1) lib/labkit/net_http_publisher.rb:47:in `block in request', activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `block in instrument', activesupport (7.0.8.4) lib/active_support/notifications/instrumenter.rb:24:in `instrument', activesupport (7.0.8.4) lib/active_support/notifications.rb:206:in `instrument', gitlab-labkit (0.36.1) lib/labkit/net_http_publisher.rb:44:in `request', net-http (0.4.1) lib/net/http.rb:2299:in `block in request', net-http (0.4.1) lib/net/http.rb:1570:in `start', net-http (0.4.1) lib/net/http.rb:2297:in `request', gitlab-labkit (0.36.1) lib/labkit/net_http_publisher.rb:40:in `request', httparty (0.21.0) lib/httparty/request.rb:156:in `perform', httparty (0.21.0) lib/httparty.rb:612:in `perform_request', gems/gitlab-http/lib/gitlab/http_v2/client.rb:96:in `sync_perform_request', gems/gitlab-http/lib/gitlab/http_v2/client.rb:68:in `perform_request', httparty (0.21.0) lib/httparty.rb:542:in `post', gems/gitlab-http/lib/gitlab/http_v2.rb:12:in `post', lib/gitlab/http.rb:36:in `public_send', lib/gitlab/http.rb:36:in `block (2 levels) in singleton class', ee/lib/gitlab/llm/anthropic/client.rb:123:in `perform_messages_request', ee/lib/gitlab/llm/anthropic/client.rb:67:in `block in messages_complete', ee/lib/gitlab/llm/concerns/exponential_backoff.rb:41:in `block in run_retry_with_exponential_backoff', ee/lib/gitlab/llm/concerns/exponential_backoff.rb:40:in `loop', ee/lib/gitlab/llm/concerns/exponential_backoff.rb:40:in `run_retry_with_exponential_backoff', ee/lib/gitlab/llm/concerns/exponential_backoff.rb:28:in `retry_with_monitored_exponential_backoff', ee/lib/gitlab/llm/concerns/exponential_backoff.rb:21:in `block in retry_with_exponential_backoff', lib/gitlab/circuit_breaker/notifier.rb:24:in `notify_run', circuitbox (2.0.0) lib/circuitbox/circuit_breaker.rb:84:in `run', lib/gitlab/circuit_breaker.rb:18:in `run_with_circuit', ee/lib/gitlab/llm/concerns/exponential_backoff.rb:20:in `retry_with_exponential_backoff', ee/lib/gitlab/llm/anthropic/client.rb:66:in `messages_complete', ee/lib/gitlab/llm/anthropic/completions/review_merge_request.rb:61:in `review_response_for', ee/lib/gitlab/llm/anthropic/completions/review_merge_request.rb:29:in `block (2 levels) in execute', ee/lib/gitlab/llm/anthropic/completions/review_merge_request.rb:22:in `each', ee/lib/gitlab/llm/anthropic/completions/review_merge_request.rb:22:in `block in execute', ee/lib/gitlab/llm/anthropic/completions/review_merge_request.rb:19:in `each', ee/lib/gitlab/llm/anthropic/completions/review_merge_request.rb:19:in `execute', ee/app/services/llm/internal/completion_service.rb:32:in `block in execute', ee/app/services/llm/internal/completion_service.rb:46:in `with_tracking', ee/app/services/llm/internal/completion_service.rb:20:in `execute', ee/app/workers/llm/completion_worker.rb:68:in `perform', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:210:in `execute_job', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:180:in `block (4 levels) in process', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:180:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', ee/lib/gitlab/sidekiq_middleware/set_session/server.rb:18:in `block in call', lib/gitlab/session.rb:11:in `with_session', ee/lib/gitlab/sidekiq_middleware/set_session/server.rb:17:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/skip_jobs.rb:51:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb:29:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executed.rb:17:in `perform', lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb:44:in `perform', lib/gitlab/sidekiq_middleware/duplicate_jobs/server.rb:8:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/concurrency_limit/middleware.rb:32:in `perform', lib/gitlab/sidekiq_middleware/concurrency_limit/server.rb:8:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/click_house/migration_support/sidekiq_middleware.rb:7:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/pause_control/strategies/base.rb:31:in `perform', lib/gitlab/sidekiq_middleware/pause_control/strategy_handler.rb:22:in `perform', lib/gitlab/sidekiq_middleware/pause_control/server.rb:8:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/worker_context.rb:9:in `wrap_in_optional_context', lib/gitlab/sidekiq_middleware/worker_context/server.rb:19:in `block in call', lib/gitlab/application_context.rb:159:in `block in use', gitlab-labkit (0.36.1) lib/labkit/context.rb:35:in `with_context', lib/gitlab/application_context.rb:159:in `use', lib/gitlab/application_context.rb:88:in `with_context', lib/gitlab/sidekiq_middleware/worker_context/server.rb:17:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_status/server_middleware.rb:7:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_versioning/middleware.rb:9:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/query_analyzer.rb:7:in `block in call', lib/gitlab/database/query_analyzer.rb:40:in `within', lib/gitlab/sidekiq_middleware/query_analyzer.rb:7:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/admin_mode/server.rb:14:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/set_ip_address.rb:10:in `block in call', lib/gitlab/ip_address_state.rb:11:in `with', lib/gitlab/sidekiq_middleware/set_ip_address.rb:9:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/instrumentation_logger.rb:9:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/batch_loader.rb:7:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/extra_done_log_metadata.rb:7:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/server_metrics.rb:111:in `block in call', lib/gitlab/sidekiq_middleware/server_metrics.rb:139:in `block in instrument', lib/gitlab/metrics/background_transaction.rb:33:in `run', lib/gitlab/sidekiq_middleware/server_metrics.rb:139:in `instrument', lib/gitlab/sidekiq_middleware/server_metrics.rb:110:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/request_store_middleware.rb:8:in `block in call', gems/gitlab-safe_request_store/lib/gitlab/safe_request_store.rb:66:in `enabling_request_store', gems/gitlab-safe_request_store/lib/gitlab/safe_request_store.rb:59:in `ensure_request_store', lib/gitlab/sidekiq_middleware/request_store_middleware.rb:7:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', gitlab-labkit (0.36.1) lib/labkit/middleware/sidekiq/server.rb:21:in `block in call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:180:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', gitlab-labkit (0.36.1) lib/labkit/middleware/sidekiq/context/server.rb:16:in `block in call', gitlab-labkit (0.36.1) lib/labkit/context.rb:35:in `with_context', gitlab-labkit (0.36.1) lib/labkit/middleware/sidekiq/context/server.rb:15:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:173:in `invoke', gitlab-labkit (0.36.1) lib/labkit/middleware/sidekiq/server.rb:20:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/monitor.rb:10:in `block in call', lib/gitlab/sidekiq_daemon/monitor.rb:46:in `within_job', lib/gitlab/sidekiq_middleware/monitor.rb:9:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/shard_awareness_validator.rb:10:in `block in call', lib/gitlab/sidekiq_sharding/validator.rb:42:in `enabled', lib/gitlab/sidekiq_middleware/shard_awareness_validator.rb:9:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', lib/gitlab/sidekiq_middleware/size_limiter/server.rb:13:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', marginalia (1.11.1) lib/marginalia/sidekiq_instrumentation.rb:9:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', sentry-sidekiq (5.19.0) lib/sentry/sidekiq/sentry_context_middleware.rb:29:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:183:in `block in traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/metrics/tracking.rb:26:in `track', vendor/gems/sidekiq-7.2.4/lib/sidekiq/metrics/tracking.rb:126:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:182:in `traverse', vendor/gems/sidekiq-7.2.4/lib/sidekiq/middleware/chain.rb:173:in `invoke', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:179:in `block (3 levels) in process', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:140:in `block (6 levels) in dispatch', vendor/gems/sidekiq-7.2.4/lib/sidekiq/job_retry.rb:113:in `local', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:139:in `block (5 levels) in dispatch', vendor/gems/sidekiq-7.2.4/lib/sidekiq/rails.rb:16:in `block in call', activesupport (7.0.8.4) lib/active_support/execution_wrapper.rb:92:in `wrap', activesupport (7.0.8.4) lib/active_support/reloader.rb:72:in `block in wrap', activesupport (7.0.8.4) lib/active_support/execution_wrapper.rb:92:in `wrap', activesupport (7.0.8.4) lib/active_support/reloader.rb:71:in `wrap', vendor/gems/sidekiq-7.2.4/lib/sidekiq/rails.rb:15:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:135:in `block (4 levels) in dispatch', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:271:in `stats', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:130:in `block (3 levels) in dispatch', lib/gitlab/sidekiq_logging/structured_logger.rb:21:in `call', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:129:in `block (2 levels) in dispatch', vendor/gems/sidekiq-7.2.4/lib/sidekiq/job_retry.rb:80:in `global', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:128:in `block in dispatch', vendor/gems/sidekiq-7.2.4/lib/sidekiq/job_logger.rb:39:in `prepare', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:127:in `dispatch', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:178:in `block (2 levels) in process', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:177:in `handle_interrupt', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:177:in `block in process', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:176:in `handle_interrupt', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:176:in `process', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:82:in `process_one', vendor/gems/sidekiq-7.2.4/lib/sidekiq/processor.rb:72:in `run', vendor/gems/sidekiq-7.2.4/lib/sidekiq/component.rb:10:in `watchdog', vendor/gems/sidekiq-7.2.4/lib/sidekiq/component.rb:19:in `block in safe_thread'
This error is not visible to the user as the summary comment wasn't updated at all.
Proposed fix
-
Investigate why this specific error is happening and fix it !165771 (merged) -
Ensure that Duo Code Review always updates the summary comment whenever any error occurs, to make it visible to the user that something went wrong.
Edited by François Rosé