Skip to main content

JdwpError

Enum JdwpError 

Source
pub enum JdwpError {
    Io(Error),
    Protocol(String),
    InvalidHandshake,
    JdwpErrorCode(u16, String),
    ConnectionClosed(String),
    NotJdwpFramed(String),
    ReplyTimeout(u64),
    InvokeTimeout(u64),
    ReadOnly(String),
}

Variants§

§

Io(Error)

§

Protocol(String)

§

InvalidHandshake

§

JdwpErrorCode(u16, String)

§

ConnectionClosed(String)

The connection to the debuggee ended, carrying why it ended.

The payload is the point. Every one of these was once reported as Reply channel closed, a message produced by four different worlds — a dead socket, a dropped event consumer, a lapsed reply, and a loop that had already gone — none of which the reader could tell apart. The event loop is the only thing that knows which, and it used to log the cause at a level nobody enables and then throw the value away, so a debuggee that died mid-question was indistinguishable from a bug in this crate. See crate::eventloop.

§

NotJdwpFramed(String)

The bytes where a JDWP packet header should be are not a JDWP packet header (TEST-24, #65).

Its own variant because the remedy is different from every other protocol failure. A Protocol error means we mis-read something the debuggee legitimately sent; this means the stream itself is not ours to parse — a peer that is not a JDWP agent, a socket carrying someone else’s traffic, or a stream that has lost packet alignment. Nothing in the command is wrong, so retrying the command is pointless, and the session cannot be salvaged by reading on.

It exists because the honest version of this was being reported as its own opposite. A header whose length field reads 1701737519 was announced as Packet too large: 1701737519 bytes — a sentence that sends the reader looking for an enormous reply, when those four bytes are the ASCII text ent/ and no large packet was ever involved. The payload carries the bytes so the speaker can be identified rather than guessed at.

§

ReplyTimeout(u64)

A command was sent, the connection stayed up, and no reply arrived within the budget.

Distinct from ConnectionClosed because the remedy differs: the socket is still there, so the session is worth keeping and the question is what failed. Distinct from InvokeTimeout because nothing was being executed in the debuggee — this is the JVM not answering a question it should have answered.

§

InvokeTimeout(u64)

A debuggee invocation did not return within its budget.

Distinct from a lost reply on purpose. INVOKE_SINGLE_THREADED runs only the target thread, so a method needing a monitor held by one of the other (still suspended) threads cannot finish — the classic debugger-invocation deadlock. That is not a protocol failure and not something the caller did wrong, and it must be reported as itself rather than folded into a generic error, because the right response is different: render shallowly and move on.

“Render shallowly and move on” is what WE do, and the message now says what the DEBUGGEE does (DUMP-8, #123), because the two had been allowed to sound like the same thing. Measured on Temurin 11.0.32 and 21.0.12 against a lock held 3000 ms past a 2000 ms budget: the call completes when the lock is finally released and the JVM re-suspends the thread at that moment — 1.2 s after this side had given up, resumed the thread and moved on. From then on the thread is suspended for good. Nothing here clears it: the watchdog resumes a suspended VM, and the VM is running. So the one remedy is a caller-issued debug.continue (which decrements every thread) or debug.resume_thread, and a message that did not name it left the reader believing the cost was the two seconds.

§

ReadOnly(String)

The connection is in read-only mode and something tried to execute code in the debuggee.

Enforced at the point of invocation rather than by inspecting expressions up in the MCP layer, because invocation is reached from many directions — a toString() render, a List.get subscript, valueOf boxing, a breakpoint condition — and a text-level guard misses whichever one nobody thought of.

Trait Implementations§

Source§

impl Debug for JdwpError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for JdwpError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for JdwpError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<Error> for JdwpError

Source§

fn from(source: Error) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more