{"record":{"id":"576e653a15cd9258","repo":"termux/termux-app","slug":"dynamic-jniresult-geterrorstring-composed-at","errorCode":null,"errorMessage":"[dynamic] JniResult.getErrorString() — composed at runtime: \"Retval: {retval}\\nErrno: {errno}\\nErrmsg: {errmsg}\"","messagePattern":"\\[dynamic\\] JniResult\\.getErrorString\\(\\) — composed at runtime: \"Retval: (.+?)\\\\nErrno: (.+?)\\\\nErrmsg: (.+?)\"","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalServerSocket.java","lineNumber":168,"sourceCode":"            if (logErrorMessage)\n                Logger.logErrorExtended(LOG_TAG, error.getErrorLogString());\n            return error;\n        }\n\n        return null;\n    }\n\n    /** Implementation for {@link Closeable#close()} to close server socket. */\n    @Override\n    public synchronized void close() throws IOException {\n        Logger.logDebug(LOG_TAG, \"close\");\n\n        int fd = mLocalSocketRunConfig.getFD();\n\n        if (fd >= 0) {\n            JniResult result = LocalSocketManager.closeSocket(mLocalSocketRunConfig.getLogTitle() + \" (server)\", fd);\n            if (result == null || result.retval != 0) {\n                throw new IOException(JniResult.getErrorString(result));\n            }\n            // Update fd to signify that server socket has been closed\n            mLocalSocketRunConfig.setFD(-1);\n        }\n    }\n\n    /**\n     * Delete server socket file if not an abstract namespace socket. This will cause any existing\n     * running server to stop.\n     */\n    private Error deleteServerSocketFile() {\n        if (!mLocalSocketRunConfig.isAbstractNamespaceSocket())\n            return FileUtils.deleteSocketFile(mLocalSocketRunConfig.getTitle() + \" server socket file\", mLocalSocketRunConfig.getPath(), true);\n        else\n            return null;\n    }\n\n    /** Listen and accept new {@link LocalClientSocket}. */","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/termux/termux-app/blob/3df69d1da197dd9bd71a3bafd902dffd720576b4/termux-shared/src/main/java/com/termux/shared/net/socket/local/LocalServerSocket.java#L150-L186","documentation":"Thrown by LocalServerSocket.close() when the JNI closeSocket call returns null or a JniResult with retval != 0. The message is composed at runtime by JniResult.getErrorString() as 'Retval: {retval}\\nErrno: {errno}\\nErrmsg: {errmsg}'. This signals the native close of the server socket fd failed (e.g. EBADF because the fd was already closed, or a JNI-level fault).","triggerScenarios":"close() called twice (fd already closed, second close yields EBADF); the fd was invalidated elsewhere; JNI closeSocket raised an exception/returned a non-zero retval; the fd value is stale after the server was stopped.","commonSituations":"Double-close in a finally block; server socket already torn down by the manager; fd overwritten/corrupted; native lib not loaded so JNI returns an error result.","solutions":["Make close() idempotent: skip the JNI call when fd < 0 (it is already set to -1 after a successful close).","Ensure close() is called exactly once (use try-with-resources on the LocalServerSocket).","Inspect the JniResult errno/errmsg in the IOException message to identify EBADF vs. native fault.","If the native library failed to load, load it before any socket operation."],"exampleFix":"// before\nif (fd >= 0) {\n    JniResult result = LocalSocketManager.closeSocket(mLocalSocketRunConfig.getLogTitle() + \" (server)\", fd);\n    if (result == null || result.retval != 0) {\n        throw new IOException(JniResult.getErrorString(result));\n    }\n    mLocalSocketRunConfig.setFD(-1);\n}\n\n// after (idempotent + log instead of throwing on already-closed fd)\nif (fd >= 0) {\n    JniResult result = LocalSocketManager.closeSocket(mLocalSocketRunConfig.getLogTitle() + \" (server)\", fd);\n    mLocalSocketRunConfig.setFD(-1);\n    if (result == null || result.retval != 0) {\n        Logger.logWarn(LOG_TAG, \"closeSocket returned error on fd \" + fd + \": \" + JniResult.getErrorString(result));\n    }\n}","handlingStrategy":"try-catch","validationCode":"if (mLocalSocketRunConfig.getFD() < 0) {\n    // already closed; nothing to do\n    return;\n}","typeGuard":null,"tryCatchPattern":"try {\n    serverSocket.close();\n} catch (IOException e) {\n    // log only; close failures on an already-tearing-down socket are usually benign\n    Logger.logWarn(LOG_TAG, \"close() failed: \" + e.getMessage());\n}","preventionTips":["Make close() idempotent by skipping the JNI call when fd < 0.","Use try-with-resources so close() is invoked exactly once.","Load the native library before any socket lifecycle operation."],"tags":["socket","jni","local-socket","lifecycle","termux"],"backgroundTag":null,"analyzedSha":"3df69d1da197dd9bd71a3bafd902dffd720576b4","analyzedAt":"2026-08-13T22:46:28.294Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}