{"record":{"id":"dd86d5458fd8a7d1","repo":"vitessio/vitess","slug":"unexpected-query-ended-without-no-results-and-no","errorCode":null,"errorMessage":"unexpected: query ended without no results and no error","messagePattern":"unexpected: query ended without no results and no error","errorType":"error_code","errorClass":"SQLError","httpStatus":null,"severity":"error","filePath":"go/mysql/conn.go","lineNumber":1409,"sourceCode":"\t\t\t\t\twarnings:         0,\n\t\t\t\t\tinfo:             \"\",\n\t\t\t\t\tsessionStateData: qr.SessionStateChanges,\n\t\t\t\t}\n\t\t\t\treturn c.writeOKPacket(&ok)\n\t\t\t}\n\t\t\tif err := c.writeFields(qr); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\treturn c.writeBinaryRows(qr)\n\t})\n\n\t// If no field was sent, we expect an error.\n\tif !receivedResult {\n\t\t// This is just a failsafe. Should never happen.\n\t\tif err == nil || err == io.EOF {\n\t\t\terr = sqlerror.NewSQLErrorFromError(errors.New(\"unexpected: query ended without no results and no error\"))\n\t\t}\n\t\tif !c.writeErrorPacketFromErrorAndLog(err) {\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\tif err != nil {\n\t\t\t// A final OK (no SERVER_MORE_RESULTS_EXISTS) already terminated\n\t\t\t// the result. Appending an ERR would desynchronize the protocol,\n\t\t\t// so tear down the connection instead.\n\t\t\tif sendFinished && !okSentWithMoreResults {\n\t\t\t\tlog.Error(\"Error after OK-terminated result\", slog.String(\"connection\", c.String()), slog.Any(\"error\", err))\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tif !c.writeErrorPacketFromErrorAndLog(err) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else if !sendFinished {\n\t\t\t// Send the end packet only sendFinished is false (results were streamed).","sourceCodeStart":1391,"sourceCodeEnd":1427,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/mysql/conn.go#L1391-L1427","documentation":"In the MySQL server connection handling (ParseComQuery/response path), this failsafe error is created when a query completes having sent no result-set fields, no error packet, and err is nil or io.EOF — a protocol invariant violation that should be impossible. It is wrapped as a SQLError and written back to the client before dropping the connection.","triggerScenarios":"During handling of a COM_QUERY (or query with params/multi-statement): the callback finished without delivering fields, without an OK/EOF outcome, and without setting a non-EOF error.","commonSituations":"A bug in a query executor callback that returns silently; handler code that forgets to set err after detecting an error; corrupted protocol state after an interrupted query — not normally triggerable from client input.","solutions":["Report it as a bug with the query and Vitess version — it indicates an executor/protocol invariant violation","Verify the query-handler callback always returns either a result or a non-nil error","Upgrade to the latest Vitess patch release in case the handler bug was already fixed","Check logs preceding this error for the underlying executor failure that was swallowed"],"exampleFix":"// before (handler callback)\nreturn // silently ends without results or error\n// after\nreturn fmt.Errorf(\"query %q produced no result\", query)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil {\n    var sqlErr *sqlerror.SQLError\n    if errors.As(err, &sqlErr) { log.Errorf(\"query failsafe: %v\", sqlErr) }\n    // reconnect / retry once; persist bug if reproducible\n}","preventionTips":["Ensure executor callbacks always return results or errors","Log the full query and stack trace when this failsafe fires","Keep Vitess updated; this is an internal-invariant bug"],"tags":["mysql","protocol","failsafe","server"],"backgroundTag":"query-protocol-failsafe","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}