paperclipai/paperclip · error · PhotonError
line_unavailable
line_unavailable
Error message
Photon did not supply a dedicated line with a stable phone number
What it means
For a dedicated allocation, allocation() requires data.type === 'dedicated' plus a valid auth record, numbers record, and a finite expiresIn >= 30. If the project is not on a dedicated plan or the dedicated response lacks these fields, a PhotonError with code 'line_unavailable' is thrown because there is no stable dedicated phone line to use.
Solutions
- Confirm the Photon project has dedicated lines provisioned and active in the Photon dashboard
- If the project is now shared-mode, create a shared PhotonLineAuthentication (allocation:'shared') instead of expecting a dedicated line
- Retry later if dedicated numbers are temporarily out of stock; free or acquire numbers in the Photon console
- Verify expiresIn/auth/numbers are being returned; if the API contract changed, update the client
Example fix
// before
const auth = new PhotonLineAuthentication({ allocation: 'dedicated', projectId, lineId, phoneNumber }, secret);
// after
const inspection = await cloud.inspect(projectId, secret);
const mode = inspection.allocation; // 'shared' | 'dedicated'
const auth = new PhotonLineAuthentication({ allocation: mode, projectId, lineId, phoneNumber }, secret); Defensive patterns
Strategy: fallback
Validate before calling
const inspection = await cloud.inspect(projectId, secret);
if (inspection.allocation !== 'dedicated') {
// route to shared flow instead of expecting a dedicated line
} Try / catch
try {
const alloc = await cloud.allocation(projectId, secret);
} catch (e) {
if (e instanceof PhotonError && e.code === 'line_unavailable') {
// fall back to shared allocation or surface 'provision dedicated lines' to the operator
} else throw e;
} Prevention
- Inspect the project's allocation mode before constructing a dedicated identity
- Provision and verify dedicated numbers in the Photon console before enabling dedicated channels
- Alert on dedicated-number quota exhaustion
When it happens
Trigger: Calling allocation()/inspect() on a project whose imessage/tokens response has type 'shared' (checked after the shared branch) or a type other than 'dedicated', or a dedicated response missing auth/numbers/expiresIn or with expiresIn < 30.
Common situations: Project switched from dedicated to shared lines in the Photon console; dedicated lines not provisioned or all released; Photon account out of dedicated-number quota; API returning an unexpected shape on degraded service.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- "configJson" is required and must be an object
- CreateOS returned an invalid resource ID.
- CreateOS returned an invalid response.
- CreateOS returned an unsuccessful response.
- CreateOS returned invalid JSON.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/54560a646aebb125.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/photon/cloud.ts:241
eligible: false,
lines: [],
};
if (data.type === "shared") {
if (typeof data.token !== "string" || !data.token || data.token.length > 16_384 ||
typeof data.expiresIn !== "number" || !Number.isFinite(data.expiresIn) || data.expiresIn < 30)
throw new PhotonError("invalid_response", "Photon returned invalid shared project credentials");
inspection.eligible = true;
return { inspection, sharedToken: data.token, tokens: new Map(), expiresIn: Math.min(data.expiresIn, 86_400) };
}
if (
data.type !== "dedicated" ||
!record(data.auth) ||
!record(data.numbers) ||
typeof data.expiresIn !== "number" ||
!Number.isFinite(data.expiresIn) ||
data.expiresIn < 30
) {
throw new PhotonError(
"line_unavailable",
"Photon did not supply a dedicated line with a stable phone number",
);
}
const tokens = new Map<string, string>();
for (const [lineId, token] of Object.entries(data.auth)) {
if (
!photonLineIdSchema.safeParse(lineId).success ||
typeof token !== "string" ||
!token ||
token.length > 16_384
)
continue;
const phoneNumber = data.numbers[lineId];
if (
typeof phoneNumber !== "string" ||
!/^\+[1-9]\d{6,14}$/.test(phoneNumber)
)View on GitHub (pinned to 3f1d897a7c)