affaan-m/ECC · error · ValueError

Draft name must be a plain file name

Error message

Draft name must be a plain file name

What it means

export_draft validates the draft name against ^[A-Za-z0-9][A-Za-z0-9_. -]{0,99}$ and rejects names ending with a dot. This keeps the name a single safe path component that works as a CapCut draft folder name on all platforms. Anything with path separators, leading special characters, control characters, or trailing dots is rejected.

Solutions

  1. Use only letters, digits, underscores, dots, spaces, and hyphens, starting with an alphanumeric character
  2. Strip or replace path components: name = Path(raw).stem or re.sub(r'[^A-Za-z0-9_. -]', '_', raw)
  3. Remove trailing dots: name = name.rstrip('.')
  4. Keep the name at or under 100 characters

Example fix

// before
name = str(Path(video).with_suffix(''))  # may contain '/'

// after
name = Path(video).stem.replace(':', '-')[:100].rstrip('.') or 'draft'
Defensive patterns

Strategy: validation

Validate before calling

import re
DRAFT_NAME_RE = re.compile(r'[A-Za-z0-9][A-Za-z0-9_. -]{0,99}')
def draft_name_ok(name):
    return bool(name) and bool(DRAFT_NAME_RE.fullmatch(name)) and not name.endswith('.')

Type guard

def is_safe_draft_name(name):
    return isinstance(name, str) and bool(re.fullmatch(r'[A-Za-z0-9][A-Za-z0-9_. -]{0,99}', name)) and not name.endswith('.')

Try / catch

try:
    export_draft(files, name=name)
except ValueError as e:
    if 'plain file name' in str(e):
        export_draft(files, name=sanitize(name))

Prevention

When it happens

Trigger: Passing names containing '/' or '\\', leading dots/spaces/hyphens, names over 100 characters, names ending in '.', or empty/unicode names to export_draft.

Common situations: Deriving the draft name from a source filename including its directory; Windows-style paths leaking into the name; a user typing 'My Edit.' with a trailing period; names auto-generated with timestamps using ':' characters.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/82d13d8c2bafcdf7. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/media/capcut.py:61

def export_draft(
    files,
    drafts,
    name,
    width=1920,
    height=1080,
    fps=30,
    overwrite=False,
    cc=None,
    probe=duration_of,
):
    geometry(width, height, fps)
    if overwrite:
        raise ValueError("CapCut draft replacement is unsafe; choose a new name")
    if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_. -]{0,99}", name) or name.endswith(
        "."
    ):
        raise ValueError("Draft name must be a plain file name")
    if not files:
        raise ValueError("At least one video is required")
    prepared = []
    for filename in files:
        path = Path(filename).resolve(strict=True)
        duration = probe(path)
        if not math.isfinite(duration) or duration <= 0:
            raise ValueError(f"Invalid media duration: {path.name}")
        prepared.append((str(path), duration))
    if cc is None:
        import pycapcut as cc
    folder = cc.DraftFolder(str(drafts))
    script = folder.create_draft(name, width, height, fps=fps, allow_replace=False)
    script.add_track(cc.TrackType.video)
    elapsed = 0
    for filename, duration in prepared:
        script.add_segment(
            cc.VideoSegment(filename, cc.trange(f"{elapsed:.6f}s", f"{duration:.6f}s"))

View on GitHub (pinned to 8321021c54)