aaif-goose/goose · error

Failed to read the selected file.

Error message

Failed to read the selected file.

What it means

Shown by the schedule modal in the goose desktop app after the Electron file dialog returns a result. window.electron.selectRecipeFile() resolves with {filePath, found, error, file}; when found is false or error is set, the file at the picked path could not be read back, and the modal surfaces the localized 'Failed to read the selected file.' message as an internal validation error. This is a filesystem-level read failure at the selected path, not a YAML problem.

Source

Thrown at ui/desktop/src/components/schedule/ScheduleModal.tsx:139

        setCronExpression('0 0 14 * * *');
        if (initialDeepLink) {
          setSourceType('deeplink');
          handleDeepLinkChange(initialDeepLink);
        }
      }
    }
  }, [isOpen, schedule, initialDeepLink, handleDeepLinkChange]);

  const handleBrowseFile = async () => {
    const fileResponse = await window.electron.selectRecipeFile();
    if (fileResponse) {
      if (fileResponse.filePath.endsWith('.yaml') || fileResponse.filePath.endsWith('.yml')) {
        setRecipeSourcePath(fileResponse.filePath);
        setInternalValidationError(null);

        try {
          if (!fileResponse.found || fileResponse.error) {
            throw new Error(intl.formatMessage(i18n.failedReadFile));
          }
          const recipe = await parseRecipeFromFile(fileResponse.file);
          if (!recipe) {
            throw new Error(intl.formatMessage(i18n.failedParseRecipe));
          }
          setParsedRecipe(recipe);
          if (recipe.title) {
            setScheduleIdFromTitle(recipe.title);
          }
        } catch (e) {
          setParsedRecipe(null);
          setInternalValidationError(
            e instanceof Error ? e.message : intl.formatMessage(i18n.failedParseRecipe)
          );
        }
      } else {
        setInternalValidationError(intl.formatMessage(i18n.invalidFileType));
      }

View on GitHub (pinned to 3810898a74)

Solutions

  1. Click Browse again and reselect the file so a fresh read is attempted
  2. Verify the path still exists and is readable (ls -l on the printed recipeSourcePath)
  3. If the error field carries a specific message, address that underlying IO cause (remount storage, fix permissions)
  4. Move the recipe to a stable local location and update the schedule to point there

Example fix

// before
if (!fileResponse.found || fileResponse.error) {
  throw new Error(intl.formatMessage(i18n.failedReadFile));
}

// after
if (!fileResponse.found || fileResponse.error) {
  setParsedRecipe(null);
  setInternalValidationError(
    (typeof fileResponse.error === 'string' && fileResponse.error) ||
      intl.formatMessage(i18n.failedReadFile)
  );
  return;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const res = await window.electron.selectRecipeFile();
  if (!res?.found || res.error) {
    setParsedRecipe(null);
    setInternalValidationError(String(res?.error ?? intl.formatMessage(i18n.failedReadFile)));
    return;
  }
  setParsedRecipe(await parseRecipeFromFile(res.file));
} catch (e) {
  setParsedRecipe(null);
  setInternalValidationError(e instanceof Error ? e.message : intl.formatMessage(i18n.failedReadFile));
}

Prevention

When it happens

Trigger: The picked .yaml/.yml file is deleted or moved between the dialog opening and the read; the file exists but the process lacks read permission; the file lives on disconnected removable storage; the IPC handler returns an error field for any other IO reason.

Common situations: Reselecting a path remembered from a previous session after the file moved; files on network mounts or USB drives that went away; permission changes on the file since it was last scheduled.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/7e47890bd845cb33. Report an issue: GitHub.