{"record":{"id":"d312f59cdd67b23d","repo":"XINCGer/Unity3DTraining","slug":"skiplastfield-cannot-be-called-at-the-end-of-a-str","errorCode":null,"errorMessage":"SkipLastField cannot be called at the end of a stream","messagePattern":"SkipLastField cannot be called at the end of a stream","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs","lineNumber":400,"sourceCode":"\n        /// <summary>\n        /// Skips the data for the field with the tag we've just read.\n        /// This should be called directly after <see cref=\"ReadTag\"/>, when\n        /// the caller wishes to skip an unknown field.\n        /// </summary>\n        /// <remarks>\n        /// This method throws <see cref=\"InvalidProtocolBufferException\"/> if the last-read tag was an end-group tag.\n        /// If a caller wishes to skip a group, they should skip the whole group, by calling this method after reading the\n        /// start-group tag. This behavior allows callers to call this method on any field they don't understand, correctly\n        /// resulting in an error if an end-group tag has not been paired with an earlier start-group tag.\n        /// </remarks>\n        /// <exception cref=\"InvalidProtocolBufferException\">The last tag was an end-group tag</exception>\n        /// <exception cref=\"InvalidOperationException\">The last read operation read to the end of the logical stream</exception>\n        public void SkipLastField()\n        {\n            if (lastTag == 0)\n            {\n                throw new InvalidOperationException(\"SkipLastField cannot be called at the end of a stream\");\n            }\n            switch (WireFormat.GetTagWireType(lastTag))\n            {\n                case WireFormat.WireType.StartGroup:\n                    SkipGroup(lastTag);\n                    break;\n                case WireFormat.WireType.EndGroup:\n                    throw new InvalidProtocolBufferException(\"SkipLastField called on an end-group tag, indicating that the corresponding start-group was missing\");\n                case WireFormat.WireType.Fixed32:\n                    ReadFixed32();\n                    break;\n                case WireFormat.WireType.Fixed64:\n                    ReadFixed64();\n                    break;\n                case WireFormat.WireType.LengthDelimited:\n                    var length = ReadLength();\n                    SkipRawBytes(length);\n                    break;","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/XINCGer/Unity3DTraining/blob/016f98412ea5e11756b286736f479b66ab6216d5/NetWorkAndResources/Socket_Protobuff/Assets/Plugins/Google.Protobuf/CodedInputStream.cs#L382-L418","documentation":"SkipLastField() skips whatever field was last read via ReadTag(), but it requires a field tag to actually be pending. lastTag == 0 means ReadTag() already reached the logical end of stream, so there is nothing to skip and InvalidOperationException is thrown. It is a caller sequencing mistake, not corrupt data.","triggerScenarios":"Calling SkipLastField() after ReadTag() returned 0 (end of stream), or calling it twice in a row without an intervening ReadTag(), or calling it before any ReadTag() at all.","commonSituations":"Hand-rolled MergeFrom-style parsing loops where the 'while (tag != 0)' exit already ended the loop but a final SkipLastField() is still executed; unknown-field handling code copied from a generated parser without matching loop structure.","solutions":["Restructure the parse loop: only call SkipLastField() inside the loop when the wire type is not handled, and never after ReadTag() returns 0.","Guard the call: if (lastTag != 0) input.SkipLastField();","Let generated message classes handle unknown fields; avoid manual tag loops where possible.","Check whether code calls SkipLastField() unconditionally after loop exit — remove that call."],"exampleFix":"// before\nwhile ((tag = input.ReadTag()) != 0) { if (!HandleKnown(tag)) input.SkipLastField(); }\ninput.SkipLastField(); // stray call at end of stream\n// after\nwhile ((tag = input.ReadTag()) != 0)\n{\n    if (!HandleKnown(tag)) input.SkipLastField();\n}","handlingStrategy":"try-catch","validationCode":"if (tag == 0) return; // end of stream: nothing to skip\nif (lastTag == 0) return; input.SkipLastField();","typeGuard":"bool HasPendingField(CodedInputStream s, int lastTag) => lastTag != 0;","tryCatchPattern":"try { input.SkipLastField(); } catch (InvalidOperationException ex) { logger.LogWarning(ex, \"SkipLastField at end of stream — parse loop bug\"); }","preventionTips":["Only call SkipLastField() inside the ReadTag() loop for unhandled wire types.","Never call it after ReadTag() returned 0 or twice in a row.","Prefer generated message MergeFrom over hand-written tag loops."],"tags":["protobuf","invalid-operation","parsing"],"backgroundTag":"invalid-state-transition","analyzedSha":"016f98412ea5e11756b286736f479b66ab6216d5","analyzedAt":"2026-09-12T01:08:58.711Z","contentChangedAt":"2026-09-12T01:08:58.711Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}