ytdl-org/youtube-dl · error · HTTPError

Is a directory: %s

Error message

Is a directory: %s

What it means

Raised inside the AVM2 interpreter loop when bytecode calls a property on the String class object itself (callproperty with obj == StringClass) and the method name is anything other than the 'String' constructor. swfinterp simply has no implementations for String's static methods, so any SWF that calls e.g. String.fromCharCode hits this NotImplementedError mid-execution.

Source

Thrown at devscripts/buildserver.py:361

        super(YoutubeDLBuilder, self).build()


class DownloadBuilder(object):
    def __init__(self, **kwargs):
        self.handler = kwargs.pop('handler')
        self.srcPath = os.path.join(self.buildPath, *tuple(kwargs['path'][2:]))
        self.srcPath = os.path.abspath(os.path.normpath(self.srcPath))
        if not self.srcPath.startswith(self.buildPath):
            raise HTTPError(self.srcPath, 401)

        super(DownloadBuilder, self).__init__(**kwargs)

    def build(self):
        if not os.path.exists(self.srcPath):
            raise HTTPError('No such file', 404)
        if os.path.isdir(self.srcPath):
            raise HTTPError('Is a directory: %s' % self.srcPath, 401)

        self.handler.send_response(200)
        self.handler.send_header('Content-Type', 'application/octet-stream')
        self.handler.send_header('Content-Disposition', 'attachment; filename=%s' % os.path.split(self.srcPath)[-1])
        self.handler.send_header('Content-Length', str(os.stat(self.srcPath).st_size))
        self.handler.end_headers()

        with open(self.srcPath, 'rb') as src:
            shutil.copyfileobj(src, self.handler.wfile)

        super(DownloadBuilder, self).build()


class CleanupTempDir(object):
    def build(self):
        try:
            rmtree(self.basePath)
        except Exception as e:

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Extend the StringClass branch in swfinterp.py to handle the needed static method (fromCharCode is a two-line addition using chr()).
  2. Use patch_function to replace the calling method with a Python implementation so the unsupported call is never executed.
  3. Update youtube-dl or use yt-dlp, where the algorithm is typically reimplemented natively.

Example fix

# before (swfinterp.py, callproperty on StringClass)
else:
    raise NotImplementedError(
        'Function String.%s is not yet implemented' % mname)

# after
elif mname == 'fromCharCode':
    res = ''.join(chr(a) for a in args)
    stack.append(res)
    continue
else:
    raise NotImplementedError(
        'Function String.%s is not yet implemented' % mname)
Defensive patterns

Strategy: fallback

Try / catch

try:
    result = func(args)
except NotImplementedError as e:
    if 'Function String.' in str(e):
        # e.g. String.fromCharCode — supply it via a patched caller
        interpreter.patch_function(avm_class, caller_name,
                                   lambda a: py_equivalent(a))
        result = func(args)
    else:
        raise

Prevention

When it happens

Trigger: Interpreted ActionScript executes String.<something>(...) as a static call — String.fromCharCode(code) is by far the most common in signature-scrambling players. The interpreter's callproperty branch matches obj == StringClass, mname != 'String', and raises.

Common situations: A site's player SWF uses String.fromCharCode in its signature algorithm; youtube-dl's interpreter runs it and dies. Appears suddenly when the site rotates its player, since old players happened not to use that call.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/1fdb2b31abb3786f. Report an issue: GitHub.