Tencent/matrix · critical
fatal error
Error message
fatal error: %s
What it means
swift::Demangle::unreachable() is the Demangler's internal 'impossible state' handler: it prints 'fatal error: <Message>' to stderr and calls std::abort(). The demangler calls it whenever a Node or encoded mangled-name structure violates invariants the demangler believes cannot occur, e.g. Node destructors on unexpected node kinds, or demangling paths for specializations, metatype representations, or impl parameter/result encodings that don't match expected shapes.
Solutions
- Match the demangler version to the Swift compiler version that produced the mangled names (sync KSCrash's Demangle.cpp with the app's Swift toolchain)
- Validate/sanitize symbol names before demangling; skip symbols that don't start with the expected Swift mangling prefix
- Update KSCrash/Matrix to a version with the demangler fix for that message
- If reproducible, report the demangling crash to swift/KSCrash upstream with the offending symbol
Example fix
// before
const char *mangled = symbol;
std::string demangled = swift::Demangle::demangleSymbolAsString(mangled);
// after
if (symbol && strncmp(symbol, "$s", 2) == 0) {
std::string demangled = swift::Demangle::demangleSymbolAsString(symbol);
} else {
const char *demangled = symbol; // leave undemangled
} Defensive patterns
Strategy: type-guard
Validate before calling
bool isSwiftMangled(const char *s) { return s && (strncmp(s, "$s", 2) == 0 || strncmp(s, "_T0", 3) == 0); } Type guard
static inline bool safeToDemangle(const char *symbol) {
return symbol != nullptr && isSwiftMangled(symbol) && strlen(symbol) < 4096;
} Try / catch
// demangler abort()s; cannot catch, so guard inputs and isolate:
if (safeToDemangle(sym)) {
demangled = demangle(sym);
} else {
demangled = sym; // fallback to raw symbol
} Prevention
- Keep the bundled demangler in sync with the app's Swift toolchain version
- Never feed arbitrary/truncated strings to the demangler; verify mangling prefixes
- Pin KSCrash/Matrix versions known-good with your Xcode/Swift version
- Fuzz or smoke-test symbolication after Swift version upgrades
When it happens
Trigger: Parsing a corrupted or malformed Swift mangled symbol name that reaches an unsupported encoding path (demangleFuncSigSpecializationConstantProp, demangleMetatypeRepresentation, demangleImplParameterOrResult, isSimpleType), or a demangler bug while freeing/printing Node structures.
Common situations: Crash reporting symbolication (KSCrash CrashBlockMonitor) demangling stack frames from an unstripped Swift binary compiled by a different Swift version than the bundled demangler; hand-crafted or truncated symbol names fed to the demangler.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/a86c2c952fe4051f.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-iOS/Matrix/WCCrashBlockMonitor/KSCrash/swift/Basic/Demangle.cpp:42
#include "Demangle.h"
#include "Fallthrough.h"
#include "SwiftStrings.h"
#include "LLVM.h"
#include "Punycode.h"
//#include "UUID.h"
#include "Optional.h"
#include "StringRef.h"
#include <functional>
#include <inttypes.h>
#include <vector>
#include <cstdio>
#include <cstdlib>
using namespace swift;
using namespace Demangle;
[[noreturn]] static void unreachable(const char *Message) {
fprintf(stderr, "fatal error: %s\n", Message);
std::abort();
}
DemanglerPrinter &DemanglerPrinter::operator<<(unsigned long long n) & {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%" PRIu64, n);
Stream.append(buffer);
return *this;
}
DemanglerPrinter &DemanglerPrinter::operator<<(long long n) & {
char buffer[32];
snprintf(buffer, sizeof(buffer), "%" PRId64, n);
Stream.append(buffer);
return *this;
}
namespace {
struct QuotedString {View on GitHub (pinned to 3b8293bd65)