can1357/oh-my-pi · error

litterbox option ttl must be one of 1h, 12h, 24h, or 72h

Error message

litterbox option ttl must be one of 1h, 12h, 24h, or 72h

What it means

litterboxTtl validates the litterbox `ttl` option against the exact set Litterbox supports (1h, 12h, 24h, 72h) and throws for anything else. Litterbox's API only accepts these four expiry values; the runtime rejects arbitrary durations up front instead of getting an opaque API error.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders-anonymous.ts:92

				"catbox",
				config,
				CATBOX_UPLOAD_URL,
				multipartFile(request, "fileToUpload", fields),
			);
			const id = remoteName(url);
			const deleteAction =
				userHash && id
					? formDelete(CATBOX_UPLOAD_URL, { reqtype: "deletefiles", userhash: userHash, files: id })
					: undefined;
			return publication("catbox", request, url, { remoteId: id, delete: deleteAction });
		},
	};
}

function litterboxTtl(config: DestinationRuntimeConfig): keyof typeof LITTERBOX_TTLS {
	const ttl = optionString(config, "ttl", "24h");
	if (ttl && Object.hasOwn(LITTERBOX_TTLS, ttl)) return ttl as keyof typeof LITTERBOX_TTLS;
	throw new Error("litterbox option ttl must be one of 1h, 12h, 24h, or 72h");
}

function createLitterboxUploader(config: DestinationRuntimeConfig): BlobUploader {
	return {
		destination: "litterbox",
		async upload(request: BlobUploadRequest) {
			const ttl = litterboxTtl(config);
			const { url } = await uploadTextUrl(
				"litterbox",
				config,
				LITTERBOX_UPLOAD_URL,
				multipartFile(request, "fileToUpload", { reqtype: "fileupload", time: ttl }),
			);
			return publication("litterbox", request, url, {
				expiresAt: Date.now() + LITTERBOX_TTLS[ttl],
				remoteId: remoteName(url),
			});
		},

View on GitHub (pinned to 9690622007)

Solutions

  1. Set ttl to exactly one of "1h", "12h", "24h", or "72h" (lowercase, no spaces).
  2. Remove the ttl option entirely to use the 24h default.
  3. If you need a different expiry, choose a destination that supports arbitrary durations (e.g. tmpfiles with its own bounds).

Example fix

// before
{ "destination": "litterbox", "options": { "ttl": "48h" } }
// after
{ "destination": "litterbox", "options": { "ttl": "72h" } }
Defensive patterns

Strategy: validation

Validate before calling

const LITTERBOX_TTLS = ["1h", "12h", "24h", "72h"] as const;
const ttl = config.options.ttl ?? "24h";
if (!(LITTERBOX_TTLS as readonly string[]).includes(String(ttl))) throw new Error(`litterbox ttl must be one of ${LITTERBOX_TTLS.join(", ")}`);

Type guard

const isLitterboxTtl = (v: unknown): v is "1h" | "12h" | "24h" | "72h" => v === "1h" || v === "12h" || v === "24h" || v === "72h";

Try / catch

try {
  uploader = createLitterboxDestination(config);
} catch (err) {
  if (String(err).includes("litterbox option ttl")) {
    logger.warn("falling back to default litterbox ttl 24h");
    config.options.ttl = "24h";
    uploader = createLitterboxDestination(config);
  } else throw err;
}

Prevention

When it happens

Trigger: Configuring a litterbox destination with `ttl` set to a value outside {"1h","12h","24h","72h"} — e.g. "48h", "1d", "7d", "24 hr", or a number like 24 — so Object.hasOwn(LITTERBOX_TTLS, ttl) is false.

Common situations: Users copying tmpfiles-style duration syntax ("48h", "2d") into litterbox config, assuming any duration works, or specifying the default in a different casing ("24H").

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/d3b3d0d0a6643461. Report an issue: GitHub.