{"record":{"id":"eb88a4418207d7a0","repo":"microsoft/aspire","slug":"no-log-entry-found-in-otlp-data","errorCode":null,"errorMessage":"No log entry found in OTLP data.","messagePattern":"No log entry found in OTLP data\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Shared/ConsoleLogs/SharedAIHelpers.cs","lineNumber":93,"sourceCode":"        var logsData = jsonArray.ToJsonString(s_jsonSerializerOptions);\n\n        return (logsData, limitMessage);\n    }\n\n    /// <summary>\n    /// Converts OTLP resource logs to a single structured log JSON for AI processing.\n    /// </summary>\n    /// <param name=\"resourceLogs\">The OTLP resource logs containing log records.</param>\n    /// <param name=\"getResourceName\">Optional function to resolve resource names.</param>\n    /// <param name=\"dashboardBaseUrl\">Optional dashboard URL.</param>\n    /// <returns>The JSON string for the first log entry.</returns>\n    public static string GetStructuredLogJson(\n        IList<OtlpResourceLogsJson>? resourceLogs,\n        Func<IOtlpResource, string> getResourceName,\n        string? dashboardBaseUrl = null)\n    {\n        var logRecords = GetLogRecordsFromOtlpData(resourceLogs);\n        var logEntry = logRecords.FirstOrDefault() ?? throw new InvalidOperationException(\"No log entry found in OTLP data.\");\n        var promptContext = new PromptContext();\n        var dto = GetLogEntryDto(logEntry, promptContext, getResourceName, dashboardBaseUrl);\n\n        return dto.ToJsonString(s_jsonSerializerOptions);\n    }\n\n    /// <summary>\n    /// Converts OTLP resource spans to traces JSON for AI processing.\n    /// </summary>\n    /// <param name=\"resourceSpans\">The OTLP resource spans containing trace data.</param>\n    /// <param name=\"getResourceName\">Optional function to resolve resource names.</param>\n    /// <param name=\"dashboardBaseUrl\">Optional dashboard URL.</param>\n    /// <returns>A tuple containing the JSON string and a limit message.</returns>\n    public static (string json, string limitMessage) GetTracesJson(\n        IList<OtlpResourceSpansJson>? resourceSpans,\n        Func<IOtlpResource, string> getResourceName,\n        string? dashboardBaseUrl = null)\n    {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Shared/ConsoleLogs/SharedAIHelpers.cs#L75-L111","documentation":"GetStructuredLogJson serializes the first log record from OTLP resource-logs data into a JSON string (for AI/dashboard consumption). It throws InvalidOperationException when the OTLP payload contains no log records at all, i.e. GetLogRecordsFromOtlpData returns an empty sequence, so FirstOrDefault has nothing to return.","triggerScenarios":"Calling GetStructuredLogJson with an empty or null resourceLogs list, resource logs that contain no scope logs/records, or OTLP JSON that fails to map into any OtlpLogRecord.","commonSituations":"Passing an empty batch of logs fetched from the OTLP endpoint to an AI assistant prompt; a resource emitted resourceLogs wrapper entries with no actual records; upstream filters removed all records before the call.","solutions":["Check that resourceLogs is non-null and contains at least one log record before calling GetStructuredLogJson","Inspect GetLogRecordsFromOtlpData output to confirm the OTLP payload actually decoded records (scopeLogs, logRecords arrays present)","Guard the call site: only invoke when a prior query returned a non-empty record count","If an empty result is legitimate for your flow, handle the empty case yourself instead of forcing the throw"],"exampleFix":"// before\nvar json = SharedAIHelpers.GetStructuredLogJson(resourceLogs, getResourceName);\n// after\nvar hasRecords = SharedAIHelpers.GetLogRecordsFromOtlpData(resourceLogs).Any();\nvar json = hasRecords\n    ? SharedAIHelpers.GetStructuredLogJson(resourceLogs, getResourceName)\n    : null; // handle empty OTLP data explicitly","handlingStrategy":"validation","validationCode":"var records = SharedAIHelpers.GetLogRecordsFromOtlpData(resourceLogs);\nif (!records.Any()) return null; // skip serialization for empty OTLP data","typeGuard":null,"tryCatchPattern":"try { return SharedAIHelpers.GetStructuredLogJson(resourceLogs, getResourceName); }\ncatch (InvalidOperationException) { return null; /* empty OTLP payload */ }","preventionTips":["Check record count before invoking AI helpers","Log the raw OTLP payload size when it decodes to zero records","Filter queries upstream so empty batches skip serialization"],"tags":["otlp","logs","empty-data","invalid-operation"],"backgroundTag":"empty-result-set","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}