Skip to content

Editor.exportDocx() swallows export errors — catch returns undefined instead of rethrowing #3579

Description

@jacobjove

What happens

Editor.exportDocx() wraps its whole body in a try { … } catch. The catch logs and emits, but has no return or throw, so on any export error the method resolves to undefined and the real error only reaches stderr:

https://github.com/superdoc-dev/superdoc/blob/main/packages/super-editor/src/editors/v1/core/Editor.ts#L3916-L3920

      return result;
    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      this.emit('exception', { error: err, editor: this });
      console.error(err);
      // ← no return / no rethrow: the function resolves to `undefined`
    }
  }

Why it's a problem

A caller that does const bytes = await editor.exportDocx() gets undefined with no thrown error to catch. The downstream failure surfaces far from the cause — e.g. … is not binary (got undefined) when the bytes are later written — and the actual TypeError is buried in console.error. Anyone hitting an export-path failure has to reverse-engineer it from stderr instead of catching a rejected promise.

How it was hit

Building a headless/collab editor with no docx source: converter.convertedXml lacks the base OOXML parts, and exportDocx's header/footer export dereferences them, throwing a TypeError. The catch swallowed it to undefined. (Context: #3568 / #3569, where seeding a blank-docx template avoids the throw — but that's a workaround for that path, not for the swallowing itself, which affects every export error.)

Suggested fix

Rethrow (or return/reject) from the catch after emitting, so the error propagates to the awaiting caller:

    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      this.emit('exception', { error: err, editor: this });
      throw err; // propagate instead of resolving undefined
    }

Keeping the exception emit preserves existing observers; the change is that callers can now try/catch (or .catch) a real rejection. Same pattern appears in the sibling catch a few lines down (~L3932) and could get the same treatment. Worth checking existing consumers that may rely on the current undefined-on-error behavior before changing the contract.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions