{"record":{"id":"843c2d073131a498","repo":"termux/termux-app","slug":"dynamic-error-geterrormarkdownstring-compose","errorCode":null,"errorMessage":"[dynamic] Error.getErrorMarkdownString() — composed at runtime: \"**Error Code**: {code}\\n**Error Message ({type})**: {message}\\n\\n{stack traces}\"","messagePattern":"\\[dynamic\\] Error\\.getErrorMarkdownString\\(\\) — composed at runtime: \"\\*\\*Error Code\\*\\*: (.+?)\\\\n\\*\\*Error Message \\((.+?)\\)\\*\\*: (.+?)\\\\n\\\\n(.+?)\"","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalClientSocket.java","lineNumber":452,"sourceCode":"            MutableInt bytesRead = new MutableInt(0);\n            Error error = LocalClientSocket.this.read(bytes, bytesRead);\n            if (error != null) {\n                throw new IOException(error.getErrorMarkdownString());\n            }\n\n            if (bytesRead.value == 0) {\n                return -1;\n            }\n\n            return bytesRead.value;\n        }\n\n        @Override\n        public int available() throws IOException {\n            MutableInt available = new MutableInt(0);\n            Error error = LocalClientSocket.this.available(available);\n            if (error != null) {\n                throw new IOException(error.getErrorMarkdownString());\n            }\n            return available.value;\n        }\n    }\n\n\n\n    /** The {@link OutputStream} implementation for the {@link LocalClientSocket}. */\n    protected class SocketOutputStream extends OutputStream {\n        private final byte[] mBytes = new byte[1];\n\n        @Override\n        public void write(int b) throws IOException {\n            mBytes[0] = (byte) b;\n\n            Error error = LocalClientSocket.this.send(mBytes);\n            if (error != null) {\n                throw new IOException(error.getErrorMarkdownString());","sourceCodeStart":434,"sourceCodeEnd":470,"githubUrl":"https://github.com/termux/termux-app/blob/3df69d1da197dd9bd71a3bafd902dffd720576b4/termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalClientSocket.java#L434-L470","documentation":"Thrown by SocketInputStream.available() when LocalClientSocket.available() returns a non-null Error. The Error is rendered to a markdown string (Error Code / Error Message / stack traces) and wrapped in an IOException. available() on a local (Unix domain) socket delegates to a JNI call; any native failure (bad fd, EBADF, peer closed) surfaces here.","triggerScenarios":"The underlying socket file descriptor is closed or invalid; the peer has closed the connection; a JNI/system call in available() returns an errno (e.g. EBADF, ENOTSOCK); the socket was never successfully connected.","commonSituations":"Calling available() after close(); peer process exited mid-stream; fd invalidated by an error on a prior read/write; using the stream after the socket manager tore it down.","solutions":["Guard available() calls with a check that the socket is still open/connected.","Catch IOException around available() and treat it as 'stream ended / 0 bytes'.","Inspect the Error markdown (errno + errmsg) to find the native cause; EBADF/ECONNRESET indicate the peer closed or fd is stale.","Ensure you do not read after the socket has been closed by the manager."],"exampleFix":"// before\npublic int available() throws IOException {\n    MutableInt available = new MutableInt(0);\n    Error error = LocalClientSocket.this.available(available);\n    if (error != null) {\n        throw new IOException(error.getErrorMarkdownString());\n    }\n    return available.value;\n}\n\n// after (graceful: treat native error as 0 available on closed peer)\npublic int available() throws IOException {\n    MutableInt available = new MutableInt(0);\n    Error error = LocalClientSocket.this.available(available);\n    if (error != null) {\n        Logger.logDebug(LOG_TAG, \"available() error: \" + error.getErrorLogString());\n        return 0;\n    }\n    return available.value;\n}","handlingStrategy":"try-catch","validationCode":"if (!socket.isConnectedOrOpen()) {\n    return 0; // no bytes available\n}","typeGuard":null,"tryCatchPattern":"try {\n    return inputStream.available();\n} catch (IOException e) {\n    // treat native available() failure as 'stream ended'\n    Log.d(TAG, \"available() failed, assuming 0: \" + e.getMessage());\n    return 0;\n}","preventionTips":["Do not call available() after close().","Treat IOException from available() as a soft '0 bytes', not a fatal error, when probing.","Inspect the Error markdown (errno) to distinguish peer-closed from transient errors."],"tags":["socket","jni","io-stream","local-socket","termux"],"backgroundTag":null,"analyzedSha":"3df69d1da197dd9bd71a3bafd902dffd720576b4","analyzedAt":"2026-08-13T22:46:28.294Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}