{"record":{"id":"00498f34610ec7be","repo":"rustdesk/rustdesk","slug":"drmtap-sha-must-be-a-full-40-character-commit-sha","errorCode":null,"errorMessage":"DRMTAP_SHA must be a full 40-character commit sha, got {LIBDRMTAP_SHA!r}","messagePattern":"DRMTAP_SHA must be a full 40-character commit sha, got (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"build.py","lineNumber":456,"sourceCode":"            ('DRMTAP_REPO', LIBDRMTAP_REPO, LIBDRMTAP_REPO_PINNED),\n            ('DRMTAP_SHA', LIBDRMTAP_SHA, LIBDRMTAP_SHA_PINNED),\n            ('DRMTAP_PREBUILT_DIR', prebuilt, None),\n        )\n        if value != pinned\n    ]\n    if overridden and not DRMTAP_UNPINNED_OK:\n        raise Exception(\n            f'{\", \".join(overridden)} would build libdrmtap from something other than the pinned '\n            f'{LIBDRMTAP_REPO_PINNED} at {LIBDRMTAP_SHA_PINNED}. That is supported for local work and '\n            'cross-builds, but it has to be deliberate: set DRMTAP_ALLOW_UNPINNED=1 as well.')\n    if overridden:\n        print(f'WARNING: libdrmtap is NOT the pinned build ({\", \".join(overridden)} set)')\n    # Both are interpolated into shell commands below, and both are env-overridable, so validate\n    # their SHAPE before they get there. This is not only about a hostile environment: a truncated\n    # or abbreviated sha would otherwise reach `git fetch` and fail with something far less obvious\n    # than saying so here, and an abbreviated one would defeat the point of pinning.\n    if not re.fullmatch(r'[0-9a-f]{40}', LIBDRMTAP_SHA):\n        raise Exception(\n            f'DRMTAP_SHA must be a full 40-character commit sha, got {LIBDRMTAP_SHA!r}')\n    if not re.fullmatch(r'(https://|git@)[A-Za-z0-9._~:/@-]+', LIBDRMTAP_REPO):\n        raise Exception(f'DRMTAP_REPO does not look like a git remote url: {LIBDRMTAP_REPO!r}')\n\n\ndef _single_real_so(paths, where):\n    # Return the one real libdrmtap.so.0.* object among `paths`, failing if there are zero or several.\n    # glob order is arbitrary, so silently taking [0] could ship a stale or wrong-arch object left\n    # over from an earlier build; a mismatch should fail the build loudly instead.\n    real = sorted(p for p in paths if os.path.isfile(p) and not os.path.islink(p))\n    if len(real) != 1:\n        raise Exception(\n            f'expected exactly one real libdrmtap.so.0.* in {where}, found {len(real)}: {real}')\n    return real[0]\n\n\ndef build_libdrmtap_so():\n    # Build libdrmtap.so from the rustdesk-org fork, fetched at the pinned LIBDRMTAP_SHA. The","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/rustdesk/rustdesk/blob/7aa98d43cf1962a7a29ec16ffef42974377ef11e/build.py#L438-L474","documentation":"Error \"DRMTAP_SHA must be a full 40-character commit sha, got {LIBDRMTAP_SHA!r}\" thrown in rustdesk/rustdesk.","triggerScenarios":"Thrown at build.py:456 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"7aa98d43cf1962a7a29ec16ffef42974377ef11e","analyzedAt":"2026-08-16T06:17:34.842Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}